]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-95.3.tar.gz mac-os-x-105 mac-os-x-1051 v95.3
authorApple <opensource@apple.com>
Tue, 30 Oct 2007 23:29:53 +0000 (23:29 +0000)
committerApple <opensource@apple.com>
Tue, 30 Oct 2007 23:29:53 +0000 (23:29 +0000)
330 files changed:
doc/man/man1/dyld.1
doc/man/man1/update_dyld_shared_cache.1 [new file with mode: 0644]
doc/man/man1/update_prebinding.1 [new file with mode: 0644]
doc/man/man3/NSModule.3 [deleted file]
doc/man/man3/NSObjectFileImage.3 [deleted file]
doc/man/man3/NSObjectFileImage_priv.3 [deleted file]
doc/man/man3/dlclose.3
doc/man/man3/dlerror.3
doc/man/man3/dlopen.3
doc/man/man3/dlopen_preflight.3 [new file with mode: 0644]
doc/man/man3/dlsym.3
doc/man/man3/dyld.3
dyld.xcodeproj/kledzik.mode1v3 [new file with mode: 0644]
dyld.xcodeproj/kledzik.pbxuser [new file with mode: 0644]
dyld.xcodeproj/project.pbxproj
include/dlfcn.h
include/mach-o/dyld-update-prebinding.h [new file with mode: 0644]
include/mach-o/dyld.h
include/mach-o/dyld_gdb.h
include/mach-o/dyld_images.h [new file with mode: 0644]
include/mach-o/dyld_priv.h
launch-cache/Architectures.hpp [new file with mode: 0644]
launch-cache/CacheFileAbstraction.hpp [new file with mode: 0644]
launch-cache/FileAbstraction.hpp [new file with mode: 0644]
launch-cache/MachOBinder.hpp [new file with mode: 0644]
launch-cache/MachOFileAbstraction.hpp [new file with mode: 0644]
launch-cache/MachOLayout.hpp [new file with mode: 0644]
launch-cache/MachORebaser.hpp [new file with mode: 0644]
launch-cache/com.apple.dyld.plist [new file with mode: 0644]
launch-cache/dyld_cache_format.h [new file with mode: 0644]
launch-cache/dyld_shared_cache.defs [new file with mode: 0644]
launch-cache/update_dyld_shared_cache.cpp [new file with mode: 0644]
src/ImageLoader.cpp
src/ImageLoader.h
src/ImageLoaderMachO.cpp
src/ImageLoaderMachO.h
src/dyld.cpp
src/dyld.exp
src/dyld.h
src/dyld64.exp
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemInterface.h [new file with mode: 0644]
src/dyldLibSystemThreadHelpers.h [deleted file]
src/dyldLock.cpp
src/dyldLock.h
src/dyldNew.cpp
src/dyldStartup.s
src/dyld_debug.c
src/dyld_gdb.cpp
src/glue.c
src/strip.exp [new file with mode: 0644]
src/stub_binding_helper.s
unit-tests/bin/exit-non-zero-pass.pl
unit-tests/bin/exit-zero-pass.pl
unit-tests/bin/result-filter.pl
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/big-stack/Makefile [new file with mode: 0644]
unit-tests/test-cases/big-stack/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-basic/Makefile
unit-tests/test-cases/bundle-dont-gc/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-dont-gc/bar.c [new file with mode: 0644]
unit-tests/test-cases/bundle-dont-gc/foo.c [new file with mode: 0644]
unit-tests/test-cases/bundle-dont-gc/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-bad/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-bad/bundle.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-bad/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-fat/Makefile
unit-tests/test-cases/bundle-memory-load/Makefile
unit-tests/test-cases/bundle-multi-link/Makefile
unit-tests/test-cases/bundle-multi-link/main.c
unit-tests/test-cases/bundle-multi-load/Makefile
unit-tests/test-cases/bundle-multi-load/main.c
unit-tests/test-cases/bundle-name-ownership/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-name-ownership/bundle.c [new file with mode: 0644]
unit-tests/test-cases/bundle-name-ownership/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-private/Makefile
unit-tests/test-cases/bundle-reload/Makefile
unit-tests/test-cases/bundle-reload/bundle.cxx
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-v-dylib/main.c
unit-tests/test-cases/bundle-weak/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-weak/bundle.cxx [new file with mode: 0644]
unit-tests/test-cases/bundle-weak/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-apple/Makefile [new file with mode: 0644]
unit-tests/test-cases/crt-apple/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-argv-NULL/Makefile [new file with mode: 0644]
unit-tests/test-cases/crt-argv-NULL/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-custom/Makefile [new file with mode: 0644]
unit-tests/test-cases/crt-custom/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-custom/mystart.s [new file with mode: 0644]
unit-tests/test-cases/crt-libSystem/Makefile [new file with mode: 0644]
unit-tests/test-cases/crt-libSystem/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-result/Makefile [new file with mode: 0644]
unit-tests/test-cases/crt-result/bad.c [new file with mode: 0644]
unit-tests/test-cases/crt-result/good.c [new file with mode: 0644]
unit-tests/test-cases/deadlock/Makefile
unit-tests/test-cases/deadlock/main.c
unit-tests/test-cases/dladdr/Makefile
unit-tests/test-cases/dlclose-dylib-unload/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-unload/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-unload/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-unload/main.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-terminator-dlclose/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-terminator-dlclose/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-terminator-dlclose/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-terminator-dlclose/main.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-unload-c++/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-unload-c++/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-unload-c++/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-unload-c++/main.c [new file with mode: 0644]
unit-tests/test-cases/dlerror-clear/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlerror-clear/main.c [new file with mode: 0644]
unit-tests/test-cases/dlerror/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlerror/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_FIRST/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_FIRST/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_FIRST/base.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_FIRST/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_FIRST/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/base.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/baz.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-basic/main.c
unit-tests/test-cases/dlopen-dyld-locking/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-dyld-locking/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-dyld-locking/base.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-dyld-locking/base.h [new file with mode: 0644]
unit-tests/test-cases/dlopen-dyld-locking/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-dyld-locking/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-from-anonymous-code/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-from-anonymous-code/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-from-anonymous-code/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-in-initializer/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-in-initializer/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-in-initializer/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-up/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-up/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-up/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-up/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-up/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-up/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-up/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-up/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-basic/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/dlsym-RTLD_NEXT-missing/Makefile
unit-tests/test-cases/dlsym-RTLD_SELF/main.c
unit-tests/test-cases/dyld-func-lookup/Makefile [new file with mode: 0644]
unit-tests/test-cases/dyld-func-lookup/foo.c [new file with mode: 0644]
unit-tests/test-cases/dyld-func-lookup/main.c [new file with mode: 0644]
unit-tests/test-cases/dyld-launched-prebound/Makefile
unit-tests/test-cases/dyld-launched-prebound/main.c
unit-tests/test-cases/dyld-slide/Makefile
unit-tests/test-cases/dyld-slide/main.c
unit-tests/test-cases/executable-image-index/Makefile [new file with mode: 0644]
unit-tests/test-cases/executable-image-index/foo.c [new file with mode: 0644]
unit-tests/test-cases/executable-image-index/main.c [new file with mode: 0644]
unit-tests/test-cases/fallback-with-suid/Makefile
unit-tests/test-cases/fallback-with-suid/foo.c
unit-tests/test-cases/fallback-with-suid/main.c
unit-tests/test-cases/flat-insert/Makefile [new file with mode: 0644]
unit-tests/test-cases/flat-insert/foo.c [new file with mode: 0644]
unit-tests/test-cases/flat-insert/main.c [new file with mode: 0644]
unit-tests/test-cases/flat-lookup-everywhere/Makefile [deleted file]
unit-tests/test-cases/flat-lookup-everywhere/main.c [deleted file]
unit-tests/test-cases/framework-fallback/Makefile
unit-tests/test-cases/image-state-change/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-change/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-change/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-change/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-OFI/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-OFI/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-OFI/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-OFI/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-dlclose/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-dlclose/base.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-dlclose/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-dlclose/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-dependents-initialized/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-dependents-initialized/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-dependents-initialized/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-dependents-initialized/main.c [new file with mode: 0644]
unit-tests/test-cases/image-suffix/Makefile
unit-tests/test-cases/initializer-args/Makefile
unit-tests/test-cases/insert-libraries-with-initializer/Makefile
unit-tests/test-cases/insert-libraries-with-initializer/base.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/base.h [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/foo.c [deleted file]
unit-tests/test-cases/insert-libraries-with-initializer/foo1.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/foo2.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/insert.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/main.c
unit-tests/test-cases/lazy-binding-reg-params/Makefile
unit-tests/test-cases/lazy-binding-reg-params/foo.h
unit-tests/test-cases/loader_path/Makefile
unit-tests/test-cases/missing-symlink-framework-fallback-path/main.c
unit-tests/test-cases/operator-new/Makefile [new file with mode: 0644]
unit-tests/test-cases/operator-new/main.cxx [new file with mode: 0644]
unit-tests/test-cases/partial-library-load/Makefile
unit-tests/test-cases/pie-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/pie-big/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-big/main.c [new file with mode: 0644]
unit-tests/test-cases/pie-custom-stack/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-custom-stack/main.c [new file with mode: 0644]
unit-tests/test-cases/prebased-performance/Makefile
unit-tests/test-cases/prebased-performance/foo.c
unit-tests/test-cases/progname/Makefile [new file with mode: 0644]
unit-tests/test-cases/progname/main.c [new file with mode: 0644]
unit-tests/test-cases/re-export-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-dylib/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/re-export-framework/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-framework/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-framework/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-framework/main.c [new file with mode: 0644]
unit-tests/test-cases/re-export-sub-framework/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-sub-framework/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-sub-framework/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-sub-framework/main.c [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-coalesce/Makefile [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-coalesce/foo.cxx [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-coalesce/main.c [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-override/Makefile [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-override/foo.c [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-override/main.c [new file with mode: 0644]
unit-tests/test-cases/read-only-stubs/Makefile [new file with mode: 0644]
unit-tests/test-cases/read-only-stubs/bar.c [new file with mode: 0644]
unit-tests/test-cases/read-only-stubs/foo.c [new file with mode: 0644]
unit-tests/test-cases/read-only-stubs/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-LD_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-LD_LIBRARY_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-LD_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-basic/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-in-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-in-dylib/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-in-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-in-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-indirect/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-indirect/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-indirect/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-indirect/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-executable_path/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-executable_path/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-executable_path/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-executable_path/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-indirect-suid/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-indirect-suid/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-indirect-suid/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-indirect-suid/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/baz.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-nesting/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-nesting/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-nesting/baz.c [new file with mode: 0644]
unit-tests/test-cases/rpath-nesting/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-nesting/main.c [new file with mode: 0644]
unit-tests/test-cases/shared-cache-symlink/Makefile [new file with mode: 0644]
unit-tests/test-cases/shared-cache-symlink/main.c [new file with mode: 0644]
unit-tests/test-cases/suid-environ/Makefile
unit-tests/test-cases/suid-executable_path/Makefile [new file with mode: 0644]
unit-tests/test-cases/suid-executable_path/foo.c [new file with mode: 0644]
unit-tests/test-cases/suid-executable_path/main.c [new file with mode: 0644]
unit-tests/test-cases/template/Makefile [new file with mode: 0644]
unit-tests/test-cases/template/main.c [new file with mode: 0644]
unit-tests/test-cases/unloadable-library-residue/Makefile
unit-tests/test-cases/unloadable-library-residue/main.c
unit-tests/test-cases/weak-override/main.c
unit-tests/test-cases/weak-symbol-flat/Makefile
unit-tests/test-cases/zero-fill-segment/Makefile [new file with mode: 0644]
unit-tests/test-cases/zero-fill-segment/foo.c [new file with mode: 0644]
unit-tests/test-cases/zero-fill-segment/main.c [new file with mode: 0644]
unit-tests/test-cases/zero-fill-segment/zero.s [new file with mode: 0644]
unit-tests/test-cases/zero-length-segment/Makefile [new file with mode: 0644]
unit-tests/test-cases/zero-length-segment/foo.c [new file with mode: 0644]
unit-tests/test-cases/zero-length-segment/main.c [new file with mode: 0644]

index 9e0b776adc0a2326c08f7464e1db4811e6f6da40..0ef371a6027e1535a131a8b3093c255cae853752 100644 (file)
@@ -1,4 +1,4 @@
-.TH DYLD 1 "January 15, 2005" "Apple Computer, Inc."
+.TH DYLD 1 "March 23, 2007" "Apple Inc."
 .SH NAME
 dyld \- the dynamic link editor
 .SH SYNOPSIS
@@ -12,6 +12,8 @@ DYLD_FALLBACK_LIBRARY_PATH
 .br
 DYLD_ROOT_PATH
 .br
+DYLD_SHARED_REGION
+.br
 DYLD_INSERT_LIBRARIES
 .br
 DYLD_FORCE_FLAT_NAMESPACE
@@ -28,11 +30,9 @@ DYLD_PRINT_LIBRARIES_POST_LAUNCH
 .br
 DYLD_BIND_AT_LAUNCH
 .br
-DYLD_PREBIND_DEBUG
-.br
-DYLD_NEW_LOCAL_SHARED_REGIONS
+DYLD_NO_FIX_PREBINDING
 .br
-DYLD_IGNORE_PREBINDING
+DYLD_DISABLE_DOFS
 .br
 DYLD_PRINT_APIS
 .br
@@ -45,6 +45,8 @@ DYLD_PRINT_REBASINGS
 DYLD_PRINT_SEGMENTS
 .br
 DYLD_PRINT_STATISTICS
+.br
+DYLD_PRINT_DOFS
 .SH DESCRIPTION
 The dynamic linker uses the following environment variables.
 They affect any program that uses the dynamic linker.
@@ -118,6 +120,15 @@ to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
 This is a colon separated list of directories.  The dynamic linker will prepend each of
 this directory paths to every image access until a file is found.    
 .TP
+.B DYLD_SHARED_REGION 
+This can be "use" (the default), "avoid", or "private".  Settting 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()
+back in a private copy of the dyld shared cache in the shared region address
+range. This is only useful if the shared cache on disk has been updated 
+and is different than the shared cache in use.
+.TP
 .B DYLD_INSERT_LIBRARIES
 This is a colon separated list of dynamic libraries to load before the ones
 specified in the program.  This lets you test new modules of existing dynamic
@@ -163,74 +174,22 @@ but the printing starts after the program gets to its entry point.
 .TP
 .B DYLD_BIND_AT_LAUNCH
 When this is set, the dynamic linker binds all undefined symbols
-the program needs at launch time. This includes function symbols that can are normally lazily bound at the time of their first call.
-.TP
-.B DYLD_PREBIND_DEBUG
-When this is set, the dynamic linker prints diagnostics about 
-launching prebound programs and libraries. This lets you determine why a
-program is not being launched prebound.
-You can view the recorded library time stamps with the
-.B \-Lv
-option to
-.IR otool (1).
-.TP
-.PP
-For secure programs that are UNIX set uid or set gid, the dynamic linker will
-not use the dyld environment variables for path searching and library insertion,
-unless the program is run as the real user.  For secure programs, the dynamic
-linker clears out the value of the dyld path and insertion environment
-variables.  This is so that if a program is
-.IR exec (2)'ed
-from a secure program too will not have it's libraries searched for, as well.
-For statically linked secure programs that
-.IR exec (2) 
-other programs that might use the dynamic linker, they too should clear out the
-values of the dyld path and insertion environment variables.
-.TP
-.B DYLD_NEW_LOCAL_SHARED_REGIONS
-When set, the dynamic linker directs the system to provide a new set of shared
-regions as the repository for library load requests for dynamic libraries
-built with
-.SM MH_SPLIT_SEGS
-(split shared libraries).
-
-Split shared libraries reside in a defined contiguous region of address space
-in all dynamic linker runtime processes.  This space is backed by named regions
-or sub-maps.  These sub-maps are owned by the system and items which are to
-mapped into them must be mapped via the
-.IR load_shared_file (2)
-call.  The use of
-sub-maps promotes a high degree of system resource sharing between the
-processes which incorporate and use them.  However, some processes require
-either additional or different libraries to be loaded into the shared region.
-While there is some space available within the shared region for alternate and
-new shared libraries, it is inappropriate to use that area for temporary or
-private libraries.  Setting the
-.SM DYLD_NEW_LOCAL_SHARED_REGIONS
-flag will cause
-all children of the current process to have their own set of sub-maps.  In this
-way the libraries found in the children's submaps will not be caused to be
-present in the submaps shared by the rest of the system.
-
-.SM DYLD_NEW_LOCAL_SHARED_REGIONS
-should be set by anyone wishing to run
-non-standard or temporary split shared libraries by setting an explicit path to
-point to them.  i.e. by using the DYLD_LIBRARY_PATH environment variable
-instead of changing the root by executing a
-.IR chroot (2)
-call.
+the program needs at launch time. This includes function symbols that can are normally 
+lazily bound at the time of their first call.
 .TP
 .B DYLD_PRINT_STATISTICS
 Right before the process's main() is called, dyld prints out information about how
 dyld spent its time.  Useful for analyzing launch performance.
 .TP
-.B DYLD_IGNORE_PREBINDING { app | all }
-Valid values are "app", "all", and "" (empty).  The variable is useful for testing 
-how various mixes of prebound and unprebound libraries perform.  When set to "all", 
-all prebinding is ignored.  That is, dyld fixes up any prebound images as if the prebinding
-in it was invalid.  When set to "all", just the prebinding information in main 
-executables is ignored. When set the nothing, the prebinding in split-seg libraries 
-is used, by all other prebinding is ignored.
+.B DYLD_NO_FIX_PREBINDING
+Normally, dyld will trigger the dyld shared cache to be regenerated if it notices
+the cache is out of date while launching a process.  If this environment variable
+is set, dyld will not trigger a cache rebuild.  This is useful to set while installing
+a large set of OS dylibs, to ensure the cache is not regenerated until the install
+is complete.
+.TP
+.B DYLD_DISABLE_DOFS 
+Causes dyld not register dtrace static probes with the kernel.
 .TP
 .B DYLD_PRINT_INITIALIZERS
 Causes dyld to print out a line when running each initializers in every image.  Initializers
@@ -242,12 +201,14 @@ Causes dyld to print a line whenever a dyld API is called (e.g. NSAddImage()).
 .TP
 .B DYLD_PRINT_SEGMENTS
 Causes dyld to print out a line containing the name and address range of each mach-o segment
-that dyld maps in.
+that dyld maps.  In addition it prints information about if the image was from the dyld 
+shared cache.
 .TP
 .B DYLD_PRINT_BINDINGS 
 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. 
 
 .SH "SEE ALSO"
 libtool(1), ld(1), otool(1)
diff --git a/doc/man/man1/update_dyld_shared_cache.1 b/doc/man/man1/update_dyld_shared_cache.1
new file mode 100644 (file)
index 0000000..a370962
--- /dev/null
@@ -0,0 +1,79 @@
+.Dd March 23, 2007
+.Dt update_dyld_shared_cache 1
+.Os Darwin
+.Sh NAME
+.Nm update_dyld_shared_cache
+.Nd "Updates dyld's shared cache"
+.Sh SYNOPSIS
+.Nm
+.Op Fl root Ar directory 
+.Op Fl arch Ar arch 
+.Op Fl force 
+.Op Fl debug
+.Op Fl sort_by_name 
+.Op Fl universal_boot 
+.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.
+.Pp
+The dyld shared cache
+is mapped by dyld into a process at launch time. Later, when loading
+any mach-o image, dyld will first check if is in the share cache, and if
+it is will use that pre-bound version instead of opening, mapping, and binding
+the original file.  This results in significant performance improvements to
+launch time.
+.Pp
+.Nm update_dyld_shared_cache
+scans the directory /var/db/dyld/shared_region_roots for text files containing paths to
+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.
+.Pp
+.Nm update_dyld_shared_cache
+builds a separate cache file for each architecture.  The cache files and a readable text
+map of the cached are generated to /var/db/dyld.
+.Pp
+You must be root to run this tool.
+.Pp
+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
+are created in the var/db/dyld directory of the specified directory.
+.It Fl arch Ar arch
+By default 
+.Nm update_dyld_shared_cache 
+generates cache files for all architecture that the current machine
+can execute.  You can override this behavior by specifying one or more -arch options and list
+exactly which architectures should have their shared caches updated.
+.It Fl force
+This option will cause 
+.Nm update_dyld_shared_cache
+to regenerated the shared cache files even if they appear to be already up-to-date. 
+.It Fl debug
+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
+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.
+.El
+.Sh FILES
+.Tp
+/var/db/dyld/shared_region_roots
+directory of text files with paths to mach-o images used to determine what should be in shared cache.
+.Sh SEE ALSO
+.Xr dyld 1
diff --git a/doc/man/man1/update_prebinding.1 b/doc/man/man1/update_prebinding.1
new file mode 100644 (file)
index 0000000..a441bed
--- /dev/null
@@ -0,0 +1 @@
+.so man1/update_dyld_shared_cache.1
diff --git a/doc/man/man3/NSModule.3 b/doc/man/man3/NSModule.3
deleted file mode 100644 (file)
index 3677477..0000000
+++ /dev/null
@@ -1,610 +0,0 @@
-.TH NSModule 3 "October 6, 2003" "Apple Computer, Inc."
-.SH NAME
-NSModule \- programmatic interface for working with modules and symbols
-.SH SYNOPSIS
-.nf
-.PP
-#include <mach-o/dyld.h>
-.sp .5
-typedef void * NSModule;
-.sp .5
-extern NSModule NSLinkModule(
-       NSObjectFileImage objectFileImage, 
-       const char *moduleName,
-       unsigned long options);
-.sp .5
-extern enum DYLD_BOOL NSUnLinkModule(
-       NSModule module, 
-       unsigned long options);
-.sp .5
-extern const char * NSNameOfModule(
-       NSModule m); 
-.sp .5
-extern const char * NSLibraryNameForModule(
-       NSModule m);
-.sp 2
-typedef void * NSSymbol;
-.sp .5
-extern enum DYLD_BOOL NSIsSymbolNameDefined(
-       const char *symbolName);
-.sp .5
-extern enum DYLD_BOOL NSIsSymbolNameDefinedWithHint(
-       const char *symbolName
-       const char *libraryNameHint);
-.sp .5 
-extern enum DYLD_BOOL NSIsSymbolNameDefinedInImage(
-       const struct mach_header *image,
-       const char *symbolName);
-.sp .5
-extern NSSymbol NSLookupAndBindSymbol(
-       const char *symbolName);
-.sp .5
-extern NSSymbol NSLookupAndBindSymbolWithHint(
-       const char *symbolName
-       const char *libraryNameHint);
-.sp .5
-extern NSSymbol NSLookupSymbolInModule(
-       NSModule module,
-       const char *symbolName);
-.sp .5
-extern NSSymbol NSLookupSymbolInImage(
-       const struct mach_header *image,
-       const char *symbolName,
-       unsigned long options);
-.sp .5
-extern const char * NSNameOfSymbol(
-       NSSymbol symbol);
-.sp .5
-extern void * NSAddressOfSymbol(
-       NSSymbol symbol);
-.sp .5
-extern NSModule NSModuleForSymbol(
-       NSSymbol symbol);
-.sp .5
-extern enum DYLD_BOOL NSAddLibrary(
-       const char *pathName);
-.sp .5
-extern enum DYLD_BOOL NSAddLibraryWithSearching(
-       const char *pathName);
-.sp .5
-extern const struct mach_header * NSAddImage(
-       const char *image_name,
-       unsigned long options);
-.sp .5
-extern long NSVersionOfRunTimeLibrary(
-       const char *libraryName);
-.sp .5
-extern long NSVersionOfLinkTimeLibrary(
-       const char *libraryName);
-.sp .5
-extern int _NSGetExecutablePath(
-       char *buf,
-       unsigned long *bufsize)
-.sp 2
-extern void NSInstallLinkEditErrorHandlers(
-       NSLinkEditErrorHandlers *handlers);
-.sp .5
-extern void NSLinkEditError(
-       NSLinkEditErrors *c,
-       int *errorNumber, 
-       const char **fileName,
-       const char **errorString);
-.if
-.SH "FUTURE SYNOPSIS"
-.nf
-.PP
-extern NSModule NSReplaceModule(
-       NSModule moduleToReplace,
-       NSObjectFileImage newObjectFileImage, 
-       unsigned long options);
-.fi
-.PP
-These routines are the programmatic interface for working with modules and
-symbols in a program.  A program is composed of a set of images, an executable,
-plugins, and dynamic shared libraries.  An image which is an executable or a
-plugin is composed of one module containing a collection of symbols.  A dynamic
-shared library is composed of one or more modules with each of those modules
-containing a separate collection of symbols.  If a symbol is used from a module
-then all the symbols from that module are used.
-.PP
-When a program is executed it selectively binds the symbols it needs from the
-modules in the dynamic libraries that are loaded.  Normally a program is
-staticly linked against a set of dynamic shared libraries when it is built.
-So when the program is executed the dynamic linker will automaticly load those
-dynamic shared libraries.
-.PP
-A program may programmatically load plugins after it starts executing and that
-is done with two sets of API's.  The first is the API's of
-.IR NSObjectFileImage (3)
-and the second is
-.I NSLinkModule.
-Unlike modules in the dynamic libraries when a plugin is loaded it is not
-selectively bound to but always bound into the program.
-.PP
-.I NSLinkModule
-links the specified object file image into the program and returns the module
-handle for it.
-Currently the implementation is limited to only Mach-O MH_BUNDLE types which
-are used for plugins.
-A module name is specified when a module is linked so that later
-.I NSNameOfModule
-can be used with the module handle and to do things like report errors.
-If you want 
-.IR gdb (1)
-to be able to debug your module, when calling
-.I NSLinkModule
-you should pass the image path as the module name.
-When a module is linked, all libraries referenced by the module are added to
-the list of libraries to be searched.
-The parameter,
-.I options,
-can have a set of options or'ed together.  The options for
-.I NSLinkModule
-are as follows:
-.TP
-.B NSLINKMODULE_OPTION_NONE
-This specifies no options.  With this the global symbols from the module are
-made part of the global symbol table of the program.  If any errors occur the
-handlers installed with
-.I NSInstallLinkEditErrorHandlers
-are called or the default action is taken if there are no handlers.
-.TP
-.B NSLINKMODULE_OPTION_BINDNOW
-This option causes the dynamic link editor to bind all undefined references for
-the loaded module and not allow references to be bound as needed.  This affects
-all the references in the module and all of the dependent references.
-.TP
-.B NSLINKMODULE_OPTION_PRIVATE
-With this option the global symbols from the module are not made part of
-the global symbol table of the program.  The global symbols of the
-module can then be looked up using
-.I NSLookupSymbolInModule.
-.TP
-.B NSLINKMODULE_OPTION_RETURN_ON_ERROR
-With this option if errors occur while binding this module it is automaticly
-unloaded and
-.SM NULL
-is returned as the module handle.  To get the error information for the module
-that failed to load the routine
-.I NSLinkEditError
-is then used.  It has the same parameters as the link edit error handler (see
-below) except all the parameters are pointers in which the information is
-returned indirectly.
-.TP
-.B NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES
-With this option the module init routines are not called.  This is only useful
-to the fix-and-continue implementation.
-.TP 
-.B NSLINKMODULE_OPTION_TRAILING_PHYS_NAME
-With this option the parameter,
-.I moduleName
-is assumed to be a string with the logical name of the image with the physical
-name of the object file tailing after the NULL character of the logical name.
-This is only useful to the zero-link implementation.
-.PP
-.I NSUnLinkModule
-unlinks the specified module handle from the program.  Currently the 
-implementation is limited to only allow modules linked with
-.I NSLinkModule
-to be unlinked.  The parameter,
-.I options,
-can have a set of options or'ed together.  The options for
-.I NSUnLinkModule
-are as follows:
-.TP
-.B NSUNLINKMODULE_OPTION_NONE
-This specifies no options.  With this the module is unlinked from the program
-and the memory for the module is deallocated.  If any errors occur the
-handlers installed with
-.I NSInstallLinkEditErrorHandlers
-are called or the default action is taken if there are no handlers.
-.TP
-.B NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
-With this option the memory for the module is not deallocated allowing pointers
-into the module to still be valid.
-.TP
-.B NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
-With this option any lazy references (direct function calls) to symbols defined
-in the module are reset to be bound on first call again and not cause any
-undefined symbol errors.  Currently this is only implemented for the PowerPC
-architecture.
-.PP
-.I NSNameOfModule
-is passed a module handle and returns the name of the module.  If the module
-handle is invalid
-.SM NULL
-is returned.
-.PP
-.I NSLibraryNameForModule
-is passed a module handle and returns the name of the library the module is in
-if any.  If the module handle is for a module that is not in a library (in the
-executable or a plugin) or the module handle is invalid
-.SM NULL
-is returned.
-.PP
-.I NSIsSymbolNameDefined
-is passed a global symbol name (global 'C' symbols names are preceded with an
-underbar '\_') and returns
-.SM TRUE
-or
-.SM FALSE
-based on if the symbol is defined in the program's global symbol table.
-If the symbol is not defined no error occurs.
-.PP
-.I NSIsSymbolNameDefinedWithHint
-is the same as
-.I NSIsSymbolNameDefined
-but the
-.I libraryNameHint
-parameter provides a hint as to where to start the lookup in a prebound
-program.  The
-.I libraryNameHint
-parameter is matched up with the actual library install names with
-.IR strstr (3).
-.PP
-.I NSIsSymbolNameDefinedInImage
-is passed a pointer to the mach_header of a mach_header structure of a
-dynamic library being used by the program and a symbol name.  This returns
-.SM TRUE
-or FALSE
-based on if the symbol is defined in the specified image or one of the image's
-sub-frameworks or sub-umbrellas.
-If the program was built with the
-.IR ld (1)
-.B \-force_flat_namespace
-flag or executed with the environment variable
-.SM DYLD_FORCE_FLAT_NAMESPACE
-set and the pointer to a mach_header structure is not of a bundle loaded with
-the 
-.B NSLINKMODULE_OPTION_PRIVATE
-option of
-.IR NSLinkModule (3)
-then the pointer to a mach_header is ignored and the symbol is looked up in
-all the images using the first definition if found.
-.PP
-The image handle parameter for
-.I NSLookupSymbolInImage
-and
-.I NSIsSymbolNameDefinedInImage
-is a pointer to a read-only mach header structure of a dynamic library being
-used by the program.  Besides the
-.IR NSAddImage (3)
-routine the pointer to a mach header can also be obtained by using a link editor
-defined symbol as in <mach-o/ldsym.h> and described on the
-.IR ld (1)
-man page.
-Also the
-.IR dyld (3)
-routine
-.IR _dyld_get_image_header (3)
-and the mach_header pointer arguments to the call back routines called from 
-.IR _dyld_register_func_for_add_image (3)
-routines can also be used.
-.PP
-.I NSLookupAndBindSymbol
-is passed a global symbol name and looks up and binds the symbol into the
-program.
-It returns an NSSymbol for the symbol.  If any errors occur the handlers
-installed with
-.I NSInstallLinkEditErrorHandlers
-are called or the default action is taken if there are no handlers.
-.PP
-.I NSLookupAndBindSymbolWithHint
-is the same as
-.I NSLookupAndBindSymbol
-but the
-.I libraryNameHint
-parameter provides a hint as to where to start the lookup in a prebound
-program.  The
-.I libraryNameHint
-parameter is matched up with the actual library install names with
-.IR strstr (3).
-.PP
-.I NSLookupSymbolInModule
-is passed a symbol name and a module handle and looks up the symbol in that
-module.  Currently this is only implemented for module handles returned with
-.I NSLinkModule.
-If the symbol is found an NSSymbol for the symbol is returned otherwise
-.SM NULL
-is returned and no error occurs.
-.PP
-.I NSLookupSymbolInImage
-is passed a pointer to a mach_header structure of a dynamic library being used
-by the program and a symbol name.  It returns an NSSymbol for the symbol for
-defined in the specified image or the image's sub-frameworks or sub-umbrellas.
-If the program was built with the
-.IR ld (1)
-.B \-force_flat_namespace
-flag or executed with the environment variable
-.SM DYLD_FORCE_FLAT_NAMESPACE
-set and the pointer to a mach_header structure is not of a bundle loaded with
-the 
-.B NSLINKMODULE_OPTION_PRIVATE
-option of
-.IR NSLinkModule (3)
-then the pointer to a mach_header is ignored and the symbol is looked up in
-all the images using the first definition found.
-If the option
-.SM NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
-is not used if any errors occur the handlers installed with
-.I NSInstallLinkEditErrorHandlers
-are called or the default action is taken if there are no handlers.
-The options of
-.I NSLookupSymbolInImage
-are as follows:
-.TP
-.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
-Just bind the non-lazy symbols of module that defines the
-.I symbolName
-and let all lazy symbols in the module be bound on first call.  This should be
-used in the normal case for a trusted module expected to bind without any errors
-like a module in a system supplied library.
-.TP
-.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW
-Bind all the non-lazy and lazy symbols of module that defines the
-.I symbolName
-and let all dependent symbols in the needed libraries be bound as needed.  This
-would be used for a module that might not be expected bind without errors but
-links against only system supplied libraries which are expected to bind without
-any errors.
-.TP
-.B NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY
-Bind all the symbols of the module that defines the
-.I symbolName
-and all the dependent symbols of all needed libraries.  This should only be
-used for things like signal handlers and linkedit error handlers that can't
-bind other symbols when executing to handle the signal or error.
-.TP
-.B NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
-With this option if errors occur while binding the module that defines the
-.I symbolName
-then the module is automaticly unloaded and
-.SM NULL
-is returned as the NSSymbol.  To get the error information for why the module
-that failed to bind the routine
-.I NSLinkEditError
-is then used.  It has the same parameters as the link edit error handler (see
-below) except all the parameters are pointers in which the information is
-returned indirectly.
-.PP
-.I NSNameOfSymbol
-is passed an NSSymbol and returns the name of the symbol.
-.PP
-.I NSAddressOfSymbol
-is passed an NSSymbol and returns the address of the symbol.
-.PP
-.I NSModuleForSymbol
-is passed an NSSymbol and returns the NSModule that symbol is defined in.
-.PP
-.I NSAddLibrary
-is passed the file name of a dynamic shared library to be added to the search
-list.  If it is successful it returns
-.SM TRUE
-else it returns
-.SM FALSE.
-.PP
-.I NSAddLibraryWithSearching
-is passed the file name of a dynamic shared library to be added to the search
-list the file name passed will be effected by the various
-.SM DYLD
-environment variables as if this library were linked into the program.  If it
-is successful it returns
-.SM TRUE
-else it returns
-.SM FALSE.
-.PP
-.I NSAddImage
-is passed the file name of a dynamic shared library to be added to the search
-list of the program if not already loaded.  It returns a pointer to the
-mach_header structure of the dynamic library being used by the program.
-For best performance of this routine if the library is expected to be already
-loaded by the program the
-.I image_name
-should be a full path name and the same as the name recorded by the program.
-If it is a symlink then an
-.IR open (2)
-and an
-.IR fstat (2)
-are needed to determine it is the same file as one already loaded.
-.PP
-If the dynamic shared library has not already been loaded it along with all the
-needed dependent libraries are loaded.  With the options parameter
-.SM NSADDIMAGE_OPTION_NONE
-then any error in loading will cause the linkEdit error handler set by
-.IR NSInstallLinkEditErrorHandlers (3)
-to be called or the default action of printing the error and exiting to be
-taken.  The other options of
-.I NSAddImage
-are as follows:
-.TP
-.B NSADDIMAGE_OPTION_RETURN_ON_ERROR
-With this option if errors occur while loading this library it is automatically
-unloaded and
-.SM NULL
-is returned.  To get the error information for the library that failed to load
-the routine
-.I NSLinkEditError
-is then used.  It has the same parameters as the link edit error handler (see
-below) except all the parameters are pointers in which the information is
-returned indirectly.
-.TP
-.B NSADDIMAGE_OPTION_WITH_SEARCHING
-With this option the
-.I image_name
-passed for the library and all its dependents will be effected by the various
-.SM DYLD
-environment variables as if this library were linked into the program.
-.TP
-.B NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
-With this option if the
-.I image_name
-passed for the library has not already been loaded it is not loaded.  Only if
-it has been loaded the pointer to the mach_header will not be
-.SM NULL.
-.TP
-.B NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME
-When this option is specified if a later load of a dependent dynamic library
-with a file system path is needed by an image that matches the install name of
-the dynamic library loaded with this option, then the dynamic library loaded
-with the call to NSAddImage() is used in place of the dependent dynamic library.
-.PP
-.I NSVersionOfRunTimeLibrary
-is passed the install name of a dynamic shared library and returns
-current_version number of the library the program is using or \-1 if the
-program is not using that library.
-.PP
-.I NSVersionOfLinkTimeLibrary
-is passed the install name of a dynamic shared library and returns the
-current_version number of the library the executable program was built
-with or \-1 if the program was not built with that library.
-.PP
-.I _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
-buffer is not large enough, \-1 is returned and the expected buffer size is
-copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to
-the executable not a "real path" to the executable. That is the path may be
-a symbolic link and not the real file. And with deep directories the total
-bufsize needed could be more than MAXPATHLEN.
-.SH ERROR HANDLING
-.PP
-.I NSInstallLinkEditErrorHandlers
-is passed a pointer to a NSLinkEditErrorHandlers which contains three function
-pointers to be used for handling dynamic link errors.  The prototypes for these
-functions are given in the following typedef:
-.RS
-.nf
-typedef struct {
-     void     (*undefined)(const char *symbolName);
-     NSModule (*multiple)(NSSymbol s, NSModule oldModule, NSModule newModule); 
-     void     (*linkEdit)(NSLinkEditErrors errorClass, int errorNumber,
-                          const char *fileName, const char *errorString);
-} NSLinkEditErrorHandlers;
-.fi
-.RE
-.PP
-The first two functions allow the programmer to direct the link edit processing
-of undefined symbols and multiply defined symbols.
-The third function allows the programmer to catch all other link editor
-errors.
-.PP
-The state when one of the user error functions gets called will be such that no
-module will be partially loaded (except in the case of resource errors like out
-of memory and other relocation errors).
-However, with undefined symbol errors those modules referencing undefined
-symbols will be partially bound, and use of such modules can and will crash the
-program.
-.PP
-Great care should be taken when implementing these functions, as the program is
-running in a state that will crash if it uses an unbound symbol.
-To be safe, these functions should only rely on other things in the same module
-or in the executable.
-.PP
-If the user does not supply these functions, the default will be to write an
-error message on to file descriptor 2 (usually stderr) and exit the program
-(except for the
-.I linkEdit
-error handler when the
-.I NSLinkEditErrors
-is NSLinkEditWarningError, then the default is to do nothing).
-.PP
-The specified undefined handler may make calls to any of the runtime loading
-functions to add modules based on the undefined symbol name.
-After dealing with this symbol name successfully (by doing a runtime loading
-operation to resolve the undefined reference) the handler simply returns.
-If more symbol's names remain undefined the handler will be called repeatedly
-with an undefined symbol name.
-If the handler can't deal with the symbol it should not return (put up a panel,
-abort, etc) and cause the program to exit.
-Or it can remove itself as the undefined handler and return which will cause
-the default action of printing the undefined symbol names and exiting.
-.PP
-The specified multiply defined symbol handler is called during the process of
-runtime linking and thus it may not call any of the runtime loading functions
-as only one set of linking operations can be performed in the task at a time.
-The only programmatic functions that can be called from a multiply defined
-symbol handler are
-.I NSNameOfSymbol,
-.I NSNameOfModule
-and
-.I NSLibraryNameForModule
-(provided they are linked into the program before the handler is called).
-This handler returns the module handle for the symbol that is to be used for
-further link editing, either the
-.I oldModule
-or the
-.I newModule.
-It may also record one of the module handles to later take action after the 
-runtime linking process has completed (for example later unlink the module).
-The dynamic link editor updates the references to the symbol if the handler
-specifies the new symbol is to be used.
-The references which are updated are those that the compiler system generated
-as indirect references.  Initialized data and references that were created at
-runtime are not effected.
-.PP
-The specified
-.I linkEdit
-error handler is called for all other runtime linking errors.
-These other runtime linking errors are either warnings or fatal errors.
-If the user's link edit error handler function returns
-for a fatal error it will cause the program to exit.
-There is small set of major error classes which have specific error numbers.
-These numbers are be passed in the parameter
-.I errorClass.
-These major error classes include:
-.RS
-.nf
-typedef enum {
-       NSLinkEditFileAccessError,
-       NSLinkEditFileFormatError,
-       NSLinkEditMachResourceError,
-       NSLinkEditUnixResourceError,
-       NSLinkEditOtherError,
-       NSLinkEditWarningError,
-       NSLinkEditMultiplyDefinedError,
-       NSLinkEditUndefinedError
-} NSLinkEditErrors;
-.fi
-.RE
-.PP
-For the error class NSLinkEditUnixResourceError the
-.I errorNumber
-parameter will be an
-.I errno
-value (see
-.IR intro (2)).
-For the error class NSLinkEditMachResourceError the
-.I errorNumber
-parameter will be a
-.I kern_return_t
-value.
-For the error class NSLinkEditOtherError the
-.I errorNumber
-parameter will be a one of the following values:
-.RS
-.nf
-typedef enum {
-    NSOtherErrorRelocation, 
-    NSOtherErrorLazyBind,
-    NSOtherErrorIndrLoop,
-    NSOtherErrorLazyInit,
-    NSOtherErrorInvalidArgs
-} NSOtherErrorNumbers;
-.fi
-.RE
-.PP
-For all errors, an attempt to pass an error string will be made.
-In some cases such as resource errors, it may not be possible to return a
-string.
-In those cases the
-.I errorString
-parameter will be
-.sm NULL.
-.PP
-For file access errors and file format errors, an attempt to return a file name 
-will also be passed, and if that is not possible the
-.I filename
-parameter will be
-.sm NULL.
-.SH ALSO SEE
-NSObjectFileImage(3), dyld(3)
diff --git a/doc/man/man3/NSObjectFileImage.3 b/doc/man/man3/NSObjectFileImage.3
deleted file mode 100644 (file)
index c235960..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-.TH NSObjectFileImage 3 "March 14, 2003" "Apple Computer, Inc."
-.SH NAME
-NSObjectFileImage \- programmatic interface for working with Mach-O files
-.SH SYNOPSIS
-.nf
-.PP
-#include <mach-o/dyld.h>
-.sp .5
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(
-       const char *pathName,
-       NSObjectFileImage *objectFileImage);
-.sp .5
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(
-       void *address,
-       unsigned long size, 
-       NSObjectFileImage *objectFileImage);
-.sp .5
-extern NSObjectFileImageReturnCode NSCreateCoreFileImageFromFile(
-       const char *pathName,
-       NSObjectFileImage *objectFileImage);
-.sp .5
-extern enum DYLD_BOOL NSDestroyObjectFileImage(
-       NSObjectFileImage objectFileImage);
-.sp .5
-extern unsigned long NSSymbolDefinitionCountInObjectFileImage(
-       NSObjectFileImage objectFileImage);
-.sp .5
-extern const char * NSSymbolDefinitionNameInObjectFileImage(
-       NSObjectFileImage objectFileImage,
-       unsigned long ordinal);
-.sp .5
-extern unsigned long NSSymbolReferenceCountInObjectFileImage(
-       NSObjectFileImage objectFileImage);
-.sp .5
-extern const char * NSSymbolReferenceNameInObjectFileImage(
-       NSObjectFileImage objectFileImage,
-       unsigned long ordinal,
-       enum DYLD_BOOL *tentative_definition); /* can be NULL */
-.sp .5
-extern enum DYLD_BOOL NSIsSymbolDefinedInObjectFileImage(
-       NSObjectFileImage objectFileImage,
-       const char *symbolName);
-.sp .5
-extern void * NSGetSectionDataInObjectFileImage(
-       NSObjectFileImage objectFileImage,
-       const char *segmentName,
-       const char *sectionName,
-       unsigned long* size); /* can be NULL */
-.sp .5
-extern enum DYLD_BOOL NSHasModInitObjectFileImage(
-       NSObjectFileImage objectFileImage);
-.fi
-.SH DESCRIPTION
-.PP
-These routines are the programmatic interface for working with Mach-O files.
-They bring the Mach-O file into memory and the API allows the file to
-be inspected or loaded into the program.  On creation of an object file image
-it is checked to insure it is a valid format and it is compatible with the host
-machine's cpu architecture.
-.PP
-.I NSCreateObjectFileImageFromFile
-takes the parameter
-.I pathName
-as the path name to the file name in the file system and creates and returns
-an NSObjectFileImage.  Currently only
-.SM MH_BUNDLE
-files can be used with
-.I NSCreateObjectFileImageFromFile
-which can then be loaded into the program using
-.IR NSLinkModule (3).
-If the file is valid an NSObjectFileImage is returned and the return code is
-NSObjectFileImageSuccess.
-.I NSCreateObjectFileImageFromMemory
-does the same as
-.I NSCreateObjectFileImageFromFile
-but takes two parameters
-.I address
-and
-.I size
-for the Mach-O file that is in memory.
-.PP
-.I NSCreateCoreFileImageFromFile
-takes the parameter
-.I pathName
-as the path name to a core file in the file system and creates and returns
-an NSObjectFileImage.  This NSObjectFileImage can then can be loaded into a
-task with
-.IR _dyld_debug_task_from_core (3)
-to determine what libraries were loaded and which modules were linked.
-.PP
-.I NSSymbolDefinitionCountInObjectFileImage
-returns the number of symbol definitions in the NSObjectFileImage. 
-.PP
-.I NSSymbolDefinitionNameInObjectFileImage
-returns the name of the i'th symbol definitions in the NSObjectFileImage. 
-The 'C' string returned should not be freed.  If the ordinal specified is
-outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will be
-returned. 
-.PP
-.I NSSymbolReferenceCountInObjectFileImage
-returns the number of references to undefined symbols the NSObjectFileImage. 
-.PP
-.I NSSymbolReferenceNameInObjectFileImage
-returns the name of the i'th undefined symbol in the NSObjectFileImage. 
-The 'C' string returned should not be freed.  If the ordinal specified is
-outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be
-returned. 
-.PP
-.I NSIsSymbolDefinedInObjectFileImage
-returns TRUE if the specified symbol name has a definition in the
-NSObjectFileImage. 
-.PP
-.I NSGetSectionDataInObjectFileImage
-returns the address of the data for the named section in the named segment in 
-the NSObjectFileImage.  If the parameter size is not NULL, the size of the
-section is returned in size.  If the section cannot be found or a zerofill
-section, NULL is returned and the size returned is zero.
-.PP
-.I NSHasModInitObjectFileImage
-returns TRUE if the NSObjectFileImage has any module initialization routines
-and FALSE otherwise.
-
-.SH RETURN CODES
-The API's that create NSObjectFileImage's return an NSObjectFileImageReturnCode
-with the following possible values:
-.TP
-.B NSObjectFileImageSuccess
-Indicates the API was successful and it returned a valid NSObjectFileImage for
-the host machine's cpu architecture.
-.TP
-.B NSObjectFileImageFailure
-Indicates the API failed and no NSObjectFileImage was returned.  If this is
-returned an error message is printed on stderr as to the reason for the 
-failure.
-.TP
-.B NSObjectFileImageInappropriateFile
-Indicates the API failed because the file passed to it was not an appropriate
-type of object file.
-.TP
-.B NSObjectFileImageArch
-Indicates the API failed because the host machine's cpu architecture could not
-be found in the file.
-.TP
-.B NSObjectFileImageFormat
-Indicates the API failed because the Mach-O format was malformed.  If this is
-returned an error message is printed on stderr as to the format error.
-.TP
-.B NSObjectFileImageAccess
-Indicates the API failed because the file could not be accessed.
-.SH ALSO SEE
-NSModule(3), dyld(3)
diff --git a/doc/man/man3/NSObjectFileImage_priv.3 b/doc/man/man3/NSObjectFileImage_priv.3
deleted file mode 100644 (file)
index aeddd1c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-.TH NSObjectFileImage 3 "July 9, 2003" "Apple Computer, Inc."
-.SH NAME
-NSObjectFileImage_priv \- programmatic interface for working with Mach-O files
-.SH SYNOPSIS
-.nf
-.PP
-#include <mach-o/dyld_priv.h>
-.sp .5
-extern enum DYLD_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 */
-.sp .5
-extern enum DYLD_BOOL 
-NSHasModInitObjectFileImage(
-       NSObjectFileImage objectFileImage);
-.fi
-.SH DESCRIPTION
-.PP
-These routines are the programmatic interface for working with Mach-O files.
-They bring the Mach-O file into memory and the API allows the file to
-be inspected or loaded into the program.  On creation of an object file image
-it is checked to insure it is a valid format and it is compatible with the host
-machine's cpu architecture.
-.PP
-.PP
-.I NSFindSectionAndOffsetInObjectFileImage
-is supplied an imageOffset into an ObjectFileImage and returns 
-via parameters the segment/section name and offset into that section of
-that imageOffset.  It returns FALSE if the imageOffset is not 
-in any section, otherwise TRUE.  You can used the resulting sectionOffset to
-index into the data returned by NSGetSectionDataInObjectFileImage.
-.PP
-.I NSHasModInitObjectFileImage
-returns TRUE if the NSObjectFileImage has any module initialization routines
-and FALSE otherwise.
-
-.SH ALSO SEE
-NSObjectFileImage(3), NSModule(3), dyld(3)
index c966d6a00d8b9b1a5c0e14be518142e0c4d7ddae..1200e8086f1c32f5b1bad0f5b045ad3c89e4dbc8 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Sept 25, 2004
+.Dd Nov 6, 2006
 .Dt DLCLOSE 3
 .Sh NAME
 .Nm dlclose
@@ -19,6 +19,13 @@ Just before removing a dynamic library or bundle in this way, any
 termination routines in it are called.  
 .Fa handle
 is the value returned by a previous call to dlopen.
+.Pp
+Prior to Mac OS X 10.5, only bundles could be unloaded.  Starting in Mac OS X 10.5, 
+dynamic libraries may also be unloaded.  There are a couple of cases in which a
+dynamic library will never be unloaded: 1) the main executable links against it, 
+2) An API that does not supoort unloading (e.g. NSAddImage()) was used to load
+it or some other dynnamic library that depends on it, 3) the dynamic library
+is in dyld's shared cache.
 .Sh RETURN VALUES
 If
 .Fn dlclose
@@ -32,7 +39,5 @@ retrived with
 .Xr dlsym 3
 .Xr dlerror 3
 .Xr dyld 3
-.Xr NSModule 3
-.Xr NSObjectFileImage 3
 .Xr ld 1
 .Xr cc 1
index 67594b340d357b632f9fb49f3979c4ec6b3ebde8..758cc1830e6585d0b8e93f307b6a2f13c2df3d19 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Sept 25, 2004
+.Dd April 17, 2006
 .Dt DLERROR 3
 .Sh NAME
 .Nm dlerror
@@ -12,6 +12,7 @@
 returns a null-terminated character string describing the last error that
 occurred on this thread during a call to
 .Fn dlopen ,
+.Fn dlopen_preflight ,
 .Fn dlsym ,
 or
 .Fn dlclose .
@@ -27,6 +28,7 @@ where the second call follows the first immediately, the second call
 will always return a null pointer.
 .Sh SEE ALSO
 .Xr dlopen 3
+.Xr dlopen_preflight 3
 .Xr dlclose 3
 .Xr dlsym 3
 .Xr dyld 3
index e4ef8f2ecd416ed62b5ac85f5744a5f53c41908c..8f88c472915e29ad569e7d0de00cb721ebde7651 100644 (file)
@@ -1,4 +1,4 @@
-.Dd February 8, 2005
+.Dd Nov 6, 2006
 .Os
 .Dt DLOPEN 3
 .Sh NAME
@@ -63,7 +63,7 @@ RTLD_LAZY nor RTLD_NOW is specified, the default is RTLD_LAZY.
 One of the following flags may be ORed into the
 .Fa mode
 argument:
-.Bl -tag -width RTLD_GLOBALX
+.Bl -tag -width RTLD_LOCALX
 .It Dv RTLD_GLOBAL
 Symbols exported from this image (dynamic library or bundle) will be available to any 
 images build with -flat_namespace option to  
@@ -77,37 +77,82 @@ and only availble to
 .Fn dlsym
 when directly using the handle returned by this call to 
 .Fn dlopen .
+.Pp
+.El
 If neither 
 RTLD_GLOBAL nor RTLD_LOCAL is specified, the default is RTLD_GLOBAL.
+.Pp
+One of the following may be ORed into the
+.Fa mode
+argument:
+.Bl -tag -width RTLD_NODELETEX
+.It Dv RTLD_NOLOAD
+The specified image is not loaded.  However, a valid  
+.Fa handle
+is returned if the image already exists in the process. This provides a way
+to query if an image is already loaded.  The 
+.Fa handle
+returned is ref-counted, so you eventually need a corresponding call to  
+.Fn dlclose
+.It Dv RTLD_NODELETE
+The specified image is tagged so that will never be removed from the address space,
+even after all clients have released it via 
+.Fn dlclose
+.El
+.Pp
+Additionally, the following may be ORed into the
+.Fa mode
+argument:
+.Bl -tag -width RTLD_FIRSTX
+.It Dv RTLD_FIRST
+The retuned    
+.Fa handle
+is tagged so that any 
+.Fn dlsym
+calls on the 
+.Fa handle
+will only search the image specified, and not subsequent images.  If 
+.Fa path
+is NULL and the option RTLD_FIRST is used, the 
+.Fa handle 
+returned will only search the main executable.
 .El
 .Sh SEARCHING
 .Fn dlopen
-uses a series of steps to find a compatible mach-o file.  The first compatible file found is used.
+searches for a compatible Mach-O file in the directories specified by a set of environment variables and 
+the process's current working directory.
+When set, the environment variables must contain a colon-separated list of directory paths, 
+which can be absolute or relative to the current working directory. The environment variables 
+are LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, and DYLD_FALLBACK_LIBRARY_PATH. 
+The first two variables have no default value. The default value of DYLD_FALLBACK_LIBRARY_PATH
+is $HOME/lib;/usr/local/lib;/usr/lib. 
+.Fn dlopen 
+searches the directories specified in the environment variables in the order they are listed. 
 .Pp
-1) If the directory specified by 
-.Fa path 
-does not contain a slash '/' (i.e. it is a leaf name) then the environment variable LD_LIBRARY_PATH is 
-used.  LD_LIBRARY_PATH should be a colon seperated list of directories.  
+When 
+.Fa path
+doesn't contain a slash character (i.e. it is just a leaf name), 
 .Fn dlopen
-searches each directory, in the order specified, for the leaf name 
-.Fa path .
-.Pp
-2) If DYLD_LIBRARY_PATH is set, then those directories are searched, in order, 
-with the leaf name of 
-.Fa path .
+searches the following the following until it finds a compatible Mach-O file: $LD_LIBRARY_PATH, 
+$DYLD_LIBRARY_PATH, current working directory, $DYLD_FALLBACK_LIBRARY_PATH.
 .Pp
-3) If DYLD_FALLBACK_LIBRARY_PATH is set, then those directories are searched, in order
-with the leaf name of 
-.Fa path .
-If DYLD_FALLBACK_LIBRARY_PATH is not set, then the following directories are searched: $HOME/lib, /usr/local/lib, /usr/lib
-.Pp
-4) Lastly, 
+When 
+.Fa path 
+contains a slash (i.e. a full path or a partial path)
+.Fn dlopen
+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
-is tried as-is as a regular file path.  That means it might resolve relative to the current working directory. 
+).
 .Pp
 Note: There are no configuration files to control dlopen searching.  
 .Pp
-Note: Mac OS X uses "fat" files to combine 32-bit and 64-bit libraries.  This means there are no separate 32-bit and 64-bit search paths.
+Note: If the main executable is a set[ug]id binary, then all environment variables are ignored, and only a full path can be used. 
+.Pp
+Note: Mac OS X uses "universal" files to combine 32-bit and 64-bit libraries.  This means there are no separate 32-bit and 64-bit search paths.
 .Pp
 .Sh RETURN VALUES
 If 
@@ -121,6 +166,7 @@ and Peter O'Gorman <ogorman@users.sourceforge.net>.
 In Mac OS X 10.4, dlopen was rewritten to be a native part of dyld.
 .Pp
 .Sh SEE ALSO
+.Xr dlopen_preflight 3
 .Xr dlclose 3
 .Xr dlsym 3
 .Xr dlerror 3
diff --git a/doc/man/man3/dlopen_preflight.3 b/doc/man/man3/dlopen_preflight.3
new file mode 100644 (file)
index 0000000..aa27dbf
--- /dev/null
@@ -0,0 +1,33 @@
+.Dd April 17, 2006
+.Os
+.Dt DLOPEN_PREFLIGHT 3
+.Sh NAME
+.Nm dlopen_preflight
+.Nd preflight the load of a dynamic library or bundle
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft bool
+.Fn dlopen_preflight "const char* path"
+.Sh DESCRIPTION
+.Fn dlopen_preflight
+examines the mach-o file specified by 
+.Fa path .
+It checks if the file and libraries it depends on are all compatible with the current process. 
+That is, they contain the correct architecture and are not otherwise ABI incompatible. 
+.Pp
+.Fn dlopen_preflight
+was first available in Mac OS X 10.5.
+.Sh SEARCHING
+.Fn dlopen_preflight
+uses the same steps as 
+.Fn dlopen
+to find a compatible mach-o file.
+.Sh RETURN VALUES
+.Fn dlopen_preflight
+returns true on if the mach-o file is compatible.  If the file is not compatible, it returns false 
+and sets an error string that can be examined with
+.Fn dlerror .
+.Pp
+.Sh SEE ALSO
+.Xr dlopen 3
+.Xr dlerror 3
index 6072b92dc2f95c02e1b51a26639f578877bebbcc..d9afeb876aafb66990ded32988de7f3507b74c07 100644 (file)
@@ -30,7 +30,8 @@ If
 is called with the special
 .Fa handle
 .Dv RTLD_DEFAULT ,
-then every mach-o image in the process is searched in the order they were loaded.
+then all mach-o images in the process (except those loaded with dlopen(xxx, RTLD_LOCAL))
+are searched in the order they were loaded.
 This can be a costly search and should be avoided.  
 .Pp
 If
index 9e10b9012b550f251a6f13de8f09459686cc0af7..9013b81636e8d76aa7cc6c49ad9c47d062b9ac5e 100644 (file)
-.TH DYLD 3 "January 15, 2005" "Apple Computer, Inc."
-.SH NAME
-dyld \- low level programatic interface to the dynamic link editor
-.SH SYNOPSIS
-.nf
-.PP
-#include <mach-o/dyld.h>
-bool _dyld_present(void);
-.sp .5
-uint32_t _dyld_image_count(void);
-.sp .5
-const struct mach_header *_dyld_get_image_header(
-       uint32_t image_index);
-.sp .5
-intptr_t _dyld_get_image_vmaddr_slide(
-       uint32_t image_index);
-.sp .5
-const char *_dyld_get_image_name(
-       uint32_t image_index);
-.sp .5
-void _dyld_lookup_and_bind(
-       const char *symbol_name,
-       void **address,
-       NSModule *module);
-.sp .5
-void _dyld_lookup_and_bind_with_hint(
-       const char *symbol_name,
-       const char *library_name_hint,
-       void **address,
-       NSModule *module);
-.sp .5
-void _dyld_lookup_and_bind_fully(
-       const char *symbol_name,
-       void **address,
-       NSModule *module);
-.sp .5
-bool _dyld_bind_fully_image_containing_address(
-       const void *address);
-.sp .5
-bool _dyld_image_containing_address(
-       const void* address);
-.sp .5
-const struct mach_header * _dyld_get_image_header_containing_address(
-       const void* address);
-.sp .5
-bool _dyld_launched_prebound(void);
-.sp .5
-bool _dyld_all_twolevel_modules_prebound(void);
-.sp .5
-int _dyld_func_lookup(
-       const char *dyld_func_name,
-       void **address);
-.sp .5
-extern void _dyld_bind_objc_module(
-       const void *objc_module);
-.sp .5 
-extern void _dyld_get_objc_module_sect_for_module(
-       NSModule module,
-       void **objc_module,
-       size_t *size);
-.sp .5
-extern void _dyld_lookup_and_bind_objc(
-       const char *symbol_name,
-       void **address,
-       NSModule *module);
-.sp .5
-extern void _dyld_moninit(
-       void (*monaddition)(char *lowpc, char *highpc));
-.sp .5
-
-extern void _dyld_register_func_for_add_image(
-       void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide));
-.sp .5
-extern void _dyld_register_func_for_remove_image(
-       void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide));
-.sp .5
-extern void _dyld_register_func_for_link_module(
-       void (*func)(NSModule module));
-.fi
-.SH DESCRIPTION
-These routines are the low level programatic interface to the dynamic link
-editor.
-.PP
-.I _dyld_present returns non-zero if the dynamic linker is being used in the
-program and zero otherwise.  If this returns zero this rest of these functions
-should not be called and most likely crash the program if called.
-.PP
-.I _dyld_image_count
-returns the current number of images mapped in by the dynamic link editor.
-.PP
-.I _dyld_get_image_header
-returns the mach header of the image indexed by image_index.  If image_index is
-out of range NULL is returned.
-.PP
-.I _dyld_get_image_vmaddr_slide
+.Dd August 16, 2006
+.Dt dyld 3
+.Sh NAME
+.Nm _dyld_image_count,
+.Nm _dyld_get_image_header,
+.Nm _dyld_get_image_vmaddr_slide,
+.Nm _dyld_get_image_name,
+.Nm _dyld_register_func_for_add_image,
+.Nm _dyld_register_func_for_remove_image,
+.Nm NSVersionOfRunTimeLibrary,
+.Nm NSVersionOfLinkTimeLibrary
+.Nm _NSGetExecutablePath
+.Sh SYNOPSIS
+.In mach-o/dyld.h
+.Ft uint32_t
+.Fo _dyld_image_count
+.Fa "void"
+.Fc
+.Ft const struct mach_header*
+.Fo _dyld_get_image_header
+.Fa "uint32_t image_index"
+.Fc
+.Ft intptr_t
+.Fo _dyld_get_image_vmaddr_slide
+.Fa "uint32_t image_index"
+.Fc
+.Ft const char*
+.Fo _dyld_get_image_name
+.Fa "uint32_t image_index"
+.Fc
+.Ft void
+.Fo _dyld_register_func_for_add_image
+.Fa "void \*[lp]*func\*[rp]\*[lp]const struct mach_header* mh, intptr_t vmaddr_slide\*[rp]"
+.Fc
+.Ft void
+.Fo _dyld_register_func_for_remove_image
+.Fa "void \*[lp]*func\*[rp]\*[lp]const struct mach_header* mh, intptr_t vmaddr_slide\*[rp]"
+.Fc
+.Ft int32_t
+.Fo NSVersionOfRunTimeLibrary
+.Fa "const char* libraryName"
+.Fc
+.Ft int32_t
+.Fo NSVersionOfLinkTimeLibrary
+.Fa "const char* libraryName"
+.Fc
+.Ft int
+.Fo _NSGetExecutablePath
+.Fa "char* buf"
+.Fa "uint32_t* bufsize"
+.Fc
+.Sh DESCRIPTION
+These routines provide additional introspection of dyld beyond that provided by
+.Fn dlopen
+and
+.Fn dladdr
+.
+.Pp
+.Fn _dyld_image_count
+returns the current number of images mapped in by dyld. Note that using this
+count to iterate all images is not thread safe, because another thread
+may be adding or removing images during the iteration.
+.Pp
+.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.
+.Pp
+.Fn _dyld_get_image_vmaddr_slide
 returns the virtural memory address slide amount of the image indexed by
-.I image_index.
-If image_index is out of range zero is returned.
-.PP
-.I _dyld_get_image_name
+.Fa image_index.
+If
+.Fa image_index
+is out of range zero is returned.
+.Pp
+.Fn _dyld_get_image_name
 returns the name of the image indexed by
-.I image_index.
-If image_index is out of range NULL is returned.
-.PP
-.I _dyld_lookup_and_bind
-looks up the
-.I symbol_name
-and binds it into the program.  It indirectly returns the
-.I address
-and and a pointer to the
-.I module
-that defined the symbol.
-.PP
-.I _dyld_lookup_and_bind_with_hint
-is the same as
-.I _dyld_lookup_and_bind
-but the
-.I library_name_hint
-parameter provides a hint as to where to start the lookup in a prebound
-program.  The
-.I library_name_hint
-parameter is matched up with the actual library install names with
-.IR strstr (3).
-.PP
-.I _dyld_lookup_and_bind_fully
-looks up the
-.I symbol_name
-and binds it and all of its references into the program.  It indirectly returns
-the
-.I address
-and and a pointer to the
-.I module
-that defined the symbol.
-.PP
-.I _dyld_bind_fully_image_containing_address
-fully binds the image containing the specified address.  It returns TRUE if the
-address is contained in a loaded image and FALSE otherwise.
-.PP
-.I _dyld_image_containing_address
-It returns TRUE if the address is contained in an image dyld loaded and FALSE
-otherwise.
-.PP
-.I _dyld_get_image_header_containing_address
-It returns a pointer to the mach header of the image if the address is contained
-in an image dyld loaded and NULL otherwise.
-.PP
-.I _dyld_launched_prebound
-returns TRUE if the program was launched using the prebound state and FALSE
-otherwise.
-.PP
-.I_dyld_all_twolevel_modules_prebound(void);
-returns TRUE if all the libraries currently in use by the program are being used
-as two-level namespace libraries, are prebound and have all their modules bound.
-Otherwise it returns FALSE.
-.PP
-.I _dyld_func_lookup
-is passed a name,
-.I dyld_func_name,
-of a dynamic link editor function and returns the
-.I address
-of the function indirectly.  It returns non-zero if the function is found
-and zero otherwise.
-.PP
-.I _dyld_bind_objc_module
-is passed a pointer to something in an (__OBJC,__module) section and causes the
-module that is associated with that address to be bound.
-.PP
-.I _dyld_get_objc_module_sect_for_module
-is passed a module and sets a pointer to the (__OBJC,__module) section and its
-size for the specified module.
-.PP
-.I _dyld_lookup_and_bind_objc()
-is the same as _dyld_lookup_and_bind() but does not update the symbol pointers
-if the symbol is in a bound module.  The reason for this is that an objc symbol
-like
-.I .objc_class_name_Object
-is never used by a symbol pointer.  Since this is done a lot by the objc
-runtime and updating symbol pointers is not cheep it should not be done.
-.PP
-.I _dyld_moninit
-is called from the profiling runtime routine
-.IR moninit(3)
-to cause the dyld loaded code to be profiled.  It is passed a pointer to the
-the profiling runtime routine
-.IR monaddtion(3)
-to be called after an image had been mapped in.
-.PP
-.I _dyld_register_func_for_add_image
+.Fa image_index.
+The C-string continues to be owned by dyld and should not deleted.
+If 
+.Fa image_index
+is out of range NULL is returned.
+.Pp
+.Fn _dyld_register_func_for_add_image
 registers the specified function to be called when a new image is added
 (a bundle or a dynamic shared library) to the program.  When this function is
 first registered it is called for once for each image that is currently part of
-the program.
-.PP
-.I _dyld_register_func_for_remove_image
+the process.
+.Pp
+.Fn _dyld_register_func_for_remove_image
 registers the specified function to be called when an image is removed
-(a bundle or a dynamic shared library) from the program.
-.I _dyld_register_func_for_link_module
-registers the specified function to be called when a module is bound into the
-program.  When this function is first registered it is called for once for each
-module that is currently bound into the program.
+(a bundle or a dynamic shared library) from the process.
+.Pp
+.Fn NSVersionOfRunTimeLibrary
+returns the current_version number of the currently loaded dylib 
+specifed by the libraryName.  The libraryName parameter would be "bar" for /path/libbar.3.dylib and
+"Foo" for /path/Foo.framework/Versions/A/Foo.  This function returns -1 if no such library is loaded.
+.Pp
+.Fn NSVersionOfLinkTimeLibrary
+returns the current_version number that the main executable was linked
+against at build time.  The libraryName parameter would be "bar" for /path/libbar.3.dylib and
+"Foo" for /path/Foo.framework/Versions/A/Foo.  This function returns -1 if the main executable did not link
+against the specified library.
+.Pp
+.Fn _NSGetExecutablePath
+copies the path of the main executable into the buffer
+.Fa buf .
+The 
+.Fa bufsize
+parameter should initially be the size of the buffer.  This function returns 0 if the path was successfully copied.
+It returns -1 if the buffer is not large enough, and *
+.Fa bufsize
+is set to the size required. 
+Note that 
+.Fn _NSGetExecutablePath 
+will return "a path" to the executable not a "real path" to the executable. 
+That is, the path may be a symbolic link and not the real file. With deep directories the total bufsize 
+needed could be more than MAXPATHLEN.
+.Sh SEE ALSO
+.Xr dlopen 3
+.Xr dladdr 3
+.Xr dyld 1
+http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/index.html
\ No newline at end of file
diff --git a/dyld.xcodeproj/kledzik.mode1v3 b/dyld.xcodeproj/kledzik.mode1v3
new file mode 100644 (file)
index 0000000..cbe28df
--- /dev/null
@@ -0,0 +1,1377 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>ActivePerspectiveName</key>
+       <string>Project</string>
+       <key>AllowedModules</key>
+       <array>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXSmartGroupTreeModule</string>
+                       <key>Name</key>
+                       <string>Groups and Files Outline View</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXNavigatorGroup</string>
+                       <key>Name</key>
+                       <string>Editor</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>XCTaskListModule</string>
+                       <key>Name</key>
+                       <string>Task List</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>XCDetailModule</string>
+                       <key>Name</key>
+                       <string>File and Smart Group Detail Viewer</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>1</string>
+                       <key>Module</key>
+                       <string>PBXBuildResultsModule</string>
+                       <key>Name</key>
+                       <string>Detailed Build Results Viewer</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>1</string>
+                       <key>Module</key>
+                       <string>PBXProjectFindModule</string>
+                       <key>Name</key>
+                       <string>Project Batch Find Tool</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>XCProjectFormatConflictsModule</string>
+                       <key>Name</key>
+                       <string>Project Format Conflicts List</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXBookmarksModule</string>
+                       <key>Name</key>
+                       <string>Bookmarks Tool</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXClassBrowserModule</string>
+                       <key>Name</key>
+                       <string>Class Browser</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXCVSModule</string>
+                       <key>Name</key>
+                       <string>Source Code Control Tool</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXDebugBreakpointsModule</string>
+                       <key>Name</key>
+                       <string>Debug Breakpoints Tool</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>XCDockableInspector</string>
+                       <key>Name</key>
+                       <string>Inspector</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>PBXOpenQuicklyModule</string>
+                       <key>Name</key>
+                       <string>Open Quickly Tool</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>1</string>
+                       <key>Module</key>
+                       <string>PBXDebugSessionModule</string>
+                       <key>Name</key>
+                       <string>Debugger</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>1</string>
+                       <key>Module</key>
+                       <string>PBXDebugCLIModule</string>
+                       <key>Name</key>
+                       <string>Debug Console</string>
+               </dict>
+               <dict>
+                       <key>BundleLoadPath</key>
+                       <string></string>
+                       <key>MaxInstances</key>
+                       <string>n</string>
+                       <key>Module</key>
+                       <string>XCSnapshotModule</string>
+                       <key>Name</key>
+                       <string>Snapshots Tool</string>
+               </dict>
+       </array>
+       <key>BundlePath</key>
+       <string>/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources</string>
+       <key>Description</key>
+       <string>DefaultDescriptionKey</string>
+       <key>DockingSystemVisible</key>
+       <false/>
+       <key>Extension</key>
+       <string>mode1v3</string>
+       <key>FavBarConfig</key>
+       <dict>
+               <key>PBXProjectModuleGUID</key>
+               <string>F9DBB28F0CD7F5F1009A2B25</string>
+               <key>XCBarModuleItemNames</key>
+               <dict/>
+               <key>XCBarModuleItems</key>
+               <array/>
+       </dict>
+       <key>FirstTimeWindowDisplayed</key>
+       <false/>
+       <key>Identifier</key>
+       <string>com.apple.perspectives.project.mode1v3</string>
+       <key>MajorVersion</key>
+       <integer>33</integer>
+       <key>MinorVersion</key>
+       <integer>0</integer>
+       <key>Name</key>
+       <string>Default</string>
+       <key>Notifications</key>
+       <array>
+               <dict>
+                       <key>XCObserverAutoDisconnectKey</key>
+                       <true/>
+                       <key>XCObserverDefintionKey</key>
+                       <dict/>
+                       <key>XCObserverFactoryKey</key>
+                       <string>XCPerspectivesSpecificationIdentifier</string>
+                       <key>XCObserverGUIDKey</key>
+                       <string>XCObserverProjectIdentifier</string>
+                       <key>XCObserverNotificationKey</key>
+                       <string>PBXStatusBuildStateMessageNotification</string>
+                       <key>XCObserverTargetKey</key>
+                       <string>XCMainBuildResultsModuleGUID</string>
+                       <key>XCObserverTriggerKey</key>
+                       <string>awakenModuleWithObserver:</string>
+                       <key>XCObserverValidationKey</key>
+                       <dict/>
+               </dict>
+       </array>
+       <key>OpenEditors</key>
+       <array/>
+       <key>PerspectiveWidths</key>
+       <array>
+               <integer>-1</integer>
+               <integer>-1</integer>
+       </array>
+       <key>Perspectives</key>
+       <array>
+               <dict>
+                       <key>ChosenToolbarItems</key>
+                       <array>
+                               <string>active-target-popup</string>
+                               <string>active-buildstyle-popup</string>
+                               <string>active-executable-popup</string>
+                               <string>NSToolbarFlexibleSpaceItem</string>
+                               <string>buildOrClean</string>
+                               <string>build-and-goOrGo</string>
+                               <string>com.apple.ide.PBXToolbarStopButton</string>
+                               <string>get-info</string>
+                               <string>toggle-editor</string>
+                               <string>NSToolbarFlexibleSpaceItem</string>
+                               <string>com.apple.pbx.toolbar.searchfield</string>
+                       </array>
+                       <key>ControllerClassBaseName</key>
+                       <string></string>
+                       <key>IconName</key>
+                       <string>WindowOfProjectWithEditor</string>
+                       <key>Identifier</key>
+                       <string>perspective.project</string>
+                       <key>IsVertical</key>
+                       <false/>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>BecomeActive</key>
+                                       <true/>
+                                       <key>ContentConfiguration</key>
+                                       <dict>
+                                               <key>PBXBottomSmartGroupGIDs</key>
+                                               <array>
+                                                       <string>1C37FBAC04509CD000000102</string>
+                                                       <string>1C37FAAC04509CD000000102</string>
+                                                       <string>1C08E77C0454961000C914BD</string>
+                                                       <string>1C37FABC05509CD000000102</string>
+                                                       <string>1C37FABC05539CD112110102</string>
+                                                       <string>E2644B35053B69B200211256</string>
+                                                       <string>1C37FABC04509CD000100104</string>
+                                                       <string>1CC0EA4004350EF90044410B</string>
+                                                       <string>1CC0EA4004350EF90041110B</string>
+                                               </array>
+                                               <key>PBXProjectModuleGUID</key>
+                                               <string>1CE0B1FE06471DED0097A5F4</string>
+                                               <key>PBXProjectModuleLabel</key>
+                                               <string>Files</string>
+                                               <key>PBXProjectStructureProvided</key>
+                                               <string>yes</string>
+                                               <key>PBXSmartGroupTreeModuleColumnData</key>
+                                               <dict>
+                                                       <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+                                                       <array>
+                                                               <real>186</real>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+                                                       <array>
+                                                               <string>MainColumn</string>
+                                                       </array>
+                                               </dict>
+                                               <key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+                                               <dict>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+                                                       <array>
+                                                               <string>F9ED4C870630A72200DF4E74</string>
+                                                               <string>1C37FBAC04509CD000000102</string>
+                                                               <string>F9DBB28B0CD7F5F1009A2B25</string>
+                                                               <string>F9DBB28C0CD7F5F1009A2B25</string>
+                                                               <string>1C37FABC05509CD000000102</string>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+                                                       <array>
+                                                               <array>
+                                                                       <integer>14</integer>
+                                                                       <integer>11</integer>
+                                                                       <integer>6</integer>
+                                                               </array>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+                                                       <string>{{0, 102}, {186, 338}}</string>
+                                               </dict>
+                                               <key>PBXTopSmartGroupGIDs</key>
+                                               <array/>
+                                               <key>XCIncludePerspectivesSwitch</key>
+                                               <true/>
+                                               <key>XCSharingToken</key>
+                                               <string>com.apple.Xcode.GFSharingToken</string>
+                                       </dict>
+                                       <key>GeometryConfiguration</key>
+                                       <dict>
+                                               <key>Frame</key>
+                                               <string>{{0, 0}, {203, 356}}</string>
+                                               <key>GroupTreeTableConfiguration</key>
+                                               <array>
+                                                       <string>MainColumn</string>
+                                                       <real>186</real>
+                                               </array>
+                                               <key>RubberWindowFrame</key>
+                                               <string>128 669 690 397 0 0 1920 1178 </string>
+                                       </dict>
+                                       <key>Module</key>
+                                       <string>PBXSmartGroupTreeModule</string>
+                                       <key>Proportion</key>
+                                       <string>203pt</string>
+                               </dict>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CE0B20306471E060097A5F4</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>MyNewFile14.java</string>
+                                                               <key>PBXSplitModuleInNavigatorKey</key>
+                                                               <dict>
+                                                                       <key>Split0</key>
+                                                                       <dict>
+                                                                               <key>PBXProjectModuleGUID</key>
+                                                                               <string>1CE0B20406471E060097A5F4</string>
+                                                                               <key>PBXProjectModuleLabel</key>
+                                                                               <string>MyNewFile14.java</string>
+                                                                       </dict>
+                                                                       <key>SplitCount</key>
+                                                                       <string>1</string>
+                                                               </dict>
+                                                               <key>StatusBarVisibility</key>
+                                                               <true/>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {482, 0}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>128 669 690 397 0 0 1920 1178 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXNavigatorGroup</string>
+                                                       <key>Proportion</key>
+                                                       <string>0pt</string>
+                                               </dict>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CE0B20506471E060097A5F4</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Detail</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 5}, {482, 351}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>128 669 690 397 0 0 1920 1178 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>XCDetailModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>351pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>482pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Project</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>XCModuleDock</string>
+                               <string>PBXSmartGroupTreeModule</string>
+                               <string>XCModuleDock</string>
+                               <string>PBXNavigatorGroup</string>
+                               <string>XCDetailModule</string>
+                       </array>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>F9DBB28D0CD7F5F1009A2B25</string>
+                               <string>1CE0B1FE06471DED0097A5F4</string>
+                               <string>F9DBB28E0CD7F5F1009A2B25</string>
+                               <string>1CE0B20306471E060097A5F4</string>
+                               <string>1CE0B20506471E060097A5F4</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.defaultV3</string>
+               </dict>
+               <dict>
+                       <key>ControllerClassBaseName</key>
+                       <string></string>
+                       <key>IconName</key>
+                       <string>WindowOfProject</string>
+                       <key>Identifier</key>
+                       <string>perspective.morph</string>
+                       <key>IsVertical</key>
+                       <integer>0</integer>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>BecomeActive</key>
+                                       <integer>1</integer>
+                                       <key>ContentConfiguration</key>
+                                       <dict>
+                                               <key>PBXBottomSmartGroupGIDs</key>
+                                               <array>
+                                                       <string>1C37FBAC04509CD000000102</string>
+                                                       <string>1C37FAAC04509CD000000102</string>
+                                                       <string>1C08E77C0454961000C914BD</string>
+                                                       <string>1C37FABC05509CD000000102</string>
+                                                       <string>1C37FABC05539CD112110102</string>
+                                                       <string>E2644B35053B69B200211256</string>
+                                                       <string>1C37FABC04509CD000100104</string>
+                                                       <string>1CC0EA4004350EF90044410B</string>
+                                                       <string>1CC0EA4004350EF90041110B</string>
+                                               </array>
+                                               <key>PBXProjectModuleGUID</key>
+                                               <string>11E0B1FE06471DED0097A5F4</string>
+                                               <key>PBXProjectModuleLabel</key>
+                                               <string>Files</string>
+                                               <key>PBXProjectStructureProvided</key>
+                                               <string>yes</string>
+                                               <key>PBXSmartGroupTreeModuleColumnData</key>
+                                               <dict>
+                                                       <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+                                                       <array>
+                                                               <real>186</real>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+                                                       <array>
+                                                               <string>MainColumn</string>
+                                                       </array>
+                                               </dict>
+                                               <key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+                                               <dict>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+                                                       <array>
+                                                               <string>29B97314FDCFA39411CA2CEA</string>
+                                                               <string>1C37FABC05509CD000000102</string>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+                                                       <array>
+                                                               <array>
+                                                                       <integer>0</integer>
+                                                               </array>
+                                                       </array>
+                                                       <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+                                                       <string>{{0, 0}, {186, 337}}</string>
+                                               </dict>
+                                               <key>PBXTopSmartGroupGIDs</key>
+                                               <array/>
+                                               <key>XCIncludePerspectivesSwitch</key>
+                                               <integer>1</integer>
+                                               <key>XCSharingToken</key>
+                                               <string>com.apple.Xcode.GFSharingToken</string>
+                                       </dict>
+                                       <key>GeometryConfiguration</key>
+                                       <dict>
+                                               <key>Frame</key>
+                                               <string>{{0, 0}, {203, 355}}</string>
+                                               <key>GroupTreeTableConfiguration</key>
+                                               <array>
+                                                       <string>MainColumn</string>
+                                                       <real>186</real>
+                                               </array>
+                                               <key>RubberWindowFrame</key>
+                                               <string>373 269 690 397 0 0 1440 878 </string>
+                                       </dict>
+                                       <key>Module</key>
+                                       <string>PBXSmartGroupTreeModule</string>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Morph</string>
+                       <key>PreferredWidth</key>
+                       <integer>300</integer>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>XCModuleDock</string>
+                               <string>PBXSmartGroupTreeModule</string>
+                       </array>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>11E0B1FE06471DED0097A5F4</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.default.shortV3</string>
+               </dict>
+       </array>
+       <key>PerspectivesBarVisible</key>
+       <false/>
+       <key>ShelfIsVisible</key>
+       <false/>
+       <key>SourceDescription</key>
+       <string>file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec'</string>
+       <key>StatusbarIsVisible</key>
+       <true/>
+       <key>TimeStamp</key>
+       <real>215479759.49117801</real>
+       <key>ToolbarDisplayMode</key>
+       <integer>1</integer>
+       <key>ToolbarIsVisible</key>
+       <true/>
+       <key>ToolbarSizeMode</key>
+       <integer>1</integer>
+       <key>Type</key>
+       <string>Perspectives</string>
+       <key>UpdateMessage</key>
+       <string>The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature).  You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature.  Do you wish to update to the latest Workspace defaults for project '%@'?</string>
+       <key>WindowJustification</key>
+       <integer>5</integer>
+       <key>WindowOrderList</key>
+       <array>
+               <string>/tmp/ttt/dyld-95.3/dyld.xcodeproj</string>
+       </array>
+       <key>WindowString</key>
+       <string>128 669 690 397 0 0 1920 1178 </string>
+       <key>WindowToolsV3</key>
+       <array>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.build</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CD0528F0623707200166675</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>&lt;No Editor&gt;</string>
+                                                               <key>PBXSplitModuleInNavigatorKey</key>
+                                                               <dict>
+                                                                       <key>Split0</key>
+                                                                       <dict>
+                                                                               <key>PBXProjectModuleGUID</key>
+                                                                               <string>1CD052900623707200166675</string>
+                                                                       </dict>
+                                                                       <key>SplitCount</key>
+                                                                       <string>1</string>
+                                                               </dict>
+                                                               <key>StatusBarVisibility</key>
+                                                               <integer>1</integer>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {500, 215}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>192 257 500 500 0 0 1280 1002 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXNavigatorGroup</string>
+                                                       <key>Proportion</key>
+                                                       <string>218pt</string>
+                                               </dict>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>XCMainBuildResultsModuleGUID</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Build</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 222}, {500, 236}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>192 257 500 500 0 0 1280 1002 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXBuildResultsModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>236pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>458pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Build Results</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXBuildResultsModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1C78EAA5065D492600B07095</string>
+                               <string>1C78EAA6065D492600B07095</string>
+                               <string>1CD0528F0623707200166675</string>
+                               <string>XCMainBuildResultsModuleGUID</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.buildV3</string>
+                       <key>WindowString</key>
+                       <string>192 257 500 500 0 0 1280 1002 </string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.debugger</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>Debugger</key>
+                                                               <dict>
+                                                                       <key>HorizontalSplitView</key>
+                                                                       <dict>
+                                                                               <key>_collapsingFrameDimension</key>
+                                                                               <real>0.0</real>
+                                                                               <key>_indexOfCollapsedView</key>
+                                                                               <integer>0</integer>
+                                                                               <key>_percentageOfCollapsedView</key>
+                                                                               <real>0.0</real>
+                                                                               <key>isCollapsed</key>
+                                                                               <string>yes</string>
+                                                                               <key>sizes</key>
+                                                                               <array>
+                                                                                       <string>{{0, 0}, {317, 164}}</string>
+                                                                                       <string>{{317, 0}, {377, 164}}</string>
+                                                                               </array>
+                                                                       </dict>
+                                                                       <key>VerticalSplitView</key>
+                                                                       <dict>
+                                                                               <key>_collapsingFrameDimension</key>
+                                                                               <real>0.0</real>
+                                                                               <key>_indexOfCollapsedView</key>
+                                                                               <integer>0</integer>
+                                                                               <key>_percentageOfCollapsedView</key>
+                                                                               <real>0.0</real>
+                                                                               <key>isCollapsed</key>
+                                                                               <string>yes</string>
+                                                                               <key>sizes</key>
+                                                                               <array>
+                                                                                       <string>{{0, 0}, {694, 164}}</string>
+                                                                                       <string>{{0, 164}, {694, 216}}</string>
+                                                                               </array>
+                                                                       </dict>
+                                                               </dict>
+                                                               <key>LauncherConfigVersion</key>
+                                                               <string>8</string>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1C162984064C10D400B95A72</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Debug - GLUTExamples (Underwater)</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>DebugConsoleDrawerSize</key>
+                                                               <string>{100, 120}</string>
+                                                               <key>DebugConsoleVisible</key>
+                                                               <string>None</string>
+                                                               <key>DebugConsoleWindowFrame</key>
+                                                               <string>{{200, 200}, {500, 300}}</string>
+                                                               <key>DebugSTDIOWindowFrame</key>
+                                                               <string>{{200, 200}, {500, 300}}</string>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {694, 380}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>321 238 694 422 0 0 1440 878 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXDebugSessionModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Debugger</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXDebugSessionModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1CD10A99069EF8BA00B06720</string>
+                               <string>1C0AD2AB069F1E9B00FABCE6</string>
+                               <string>1C162984064C10D400B95A72</string>
+                               <string>1C0AD2AC069F1E9B00FABCE6</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.debugV3</string>
+                       <key>WindowString</key>
+                       <string>321 238 694 422 0 0 1440 878 </string>
+                       <key>WindowToolGUID</key>
+                       <string>1CD10A99069EF8BA00B06720</string>
+                       <key>WindowToolIsVisible</key>
+                       <integer>0</integer>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.find</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Dock</key>
+                                                       <array>
+                                                               <dict>
+                                                                       <key>ContentConfiguration</key>
+                                                                       <dict>
+                                                                               <key>PBXProjectModuleGUID</key>
+                                                                               <string>1CDD528C0622207200134675</string>
+                                                                               <key>PBXProjectModuleLabel</key>
+                                                                               <string>&lt;No Editor&gt;</string>
+                                                                               <key>PBXSplitModuleInNavigatorKey</key>
+                                                                               <dict>
+                                                                                       <key>Split0</key>
+                                                                                       <dict>
+                                                                                               <key>PBXProjectModuleGUID</key>
+                                                                                               <string>1CD0528D0623707200166675</string>
+                                                                                       </dict>
+                                                                                       <key>SplitCount</key>
+                                                                                       <string>1</string>
+                                                                               </dict>
+                                                                               <key>StatusBarVisibility</key>
+                                                                               <integer>1</integer>
+                                                                       </dict>
+                                                                       <key>GeometryConfiguration</key>
+                                                                       <dict>
+                                                                               <key>Frame</key>
+                                                                               <string>{{0, 0}, {781, 167}}</string>
+                                                                               <key>RubberWindowFrame</key>
+                                                                               <string>62 385 781 470 0 0 1440 878 </string>
+                                                                       </dict>
+                                                                       <key>Module</key>
+                                                                       <string>PBXNavigatorGroup</string>
+                                                                       <key>Proportion</key>
+                                                                       <string>781pt</string>
+                                                               </dict>
+                                                       </array>
+                                                       <key>Proportion</key>
+                                                       <string>50%</string>
+                                               </dict>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CD0528E0623707200166675</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Project Find</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{8, 0}, {773, 254}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>62 385 781 470 0 0 1440 878 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXProjectFindModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>50%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>428pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Project Find</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXProjectFindModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1C530D57069F1CE1000CFCEE</string>
+                               <string>1C530D58069F1CE1000CFCEE</string>
+                               <string>1C530D59069F1CE1000CFCEE</string>
+                               <string>1CDD528C0622207200134675</string>
+                               <string>1C530D5A069F1CE1000CFCEE</string>
+                               <string>1CE0B1FE06471DED0097A5F4</string>
+                               <string>1CD0528E0623707200166675</string>
+                       </array>
+                       <key>WindowString</key>
+                       <string>62 385 781 470 0 0 1440 878 </string>
+                       <key>WindowToolGUID</key>
+                       <string>1C530D57069F1CE1000CFCEE</string>
+                       <key>WindowToolIsVisible</key>
+                       <integer>0</integer>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>MENUSEPARATOR</string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.debuggerConsole</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1C78EAAC065D492600B07095</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Debugger Console</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {650, 250}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>516 632 650 250 0 0 1680 1027 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXDebugCLIModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>209pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>209pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Debugger Console</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXDebugCLIModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1C78EAAD065D492600B07095</string>
+                               <string>1C78EAAE065D492600B07095</string>
+                               <string>1C78EAAC065D492600B07095</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.consoleV3</string>
+                       <key>WindowString</key>
+                       <string>650 41 650 250 0 0 1280 1002 </string>
+                       <key>WindowToolGUID</key>
+                       <string>1C78EAAD065D492600B07095</string>
+                       <key>WindowToolIsVisible</key>
+                       <integer>0</integer>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.snapshots</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Module</key>
+                                                       <string>XCSnapshotModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Snapshots</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>XCSnapshotModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <string>Yes</string>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.snapshots</string>
+                       <key>WindowString</key>
+                       <string>315 824 300 550 0 0 1440 878 </string>
+                       <key>WindowToolIsVisible</key>
+                       <string>Yes</string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.scm</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1C78EAB2065D492600B07095</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>&lt;No Editor&gt;</string>
+                                                               <key>PBXSplitModuleInNavigatorKey</key>
+                                                               <dict>
+                                                                       <key>Split0</key>
+                                                                       <dict>
+                                                                               <key>PBXProjectModuleGUID</key>
+                                                                               <string>1C78EAB3065D492600B07095</string>
+                                                                       </dict>
+                                                                       <key>SplitCount</key>
+                                                                       <string>1</string>
+                                                               </dict>
+                                                               <key>StatusBarVisibility</key>
+                                                               <integer>1</integer>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {452, 0}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>743 379 452 308 0 0 1280 1002 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXNavigatorGroup</string>
+                                                       <key>Proportion</key>
+                                                       <string>0pt</string>
+                                               </dict>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CD052920623707200166675</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>SCM</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>ConsoleFrame</key>
+                                                               <string>{{0, 259}, {452, 0}}</string>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 7}, {452, 259}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>743 379 452 308 0 0 1280 1002 </string>
+                                                               <key>TableConfiguration</key>
+                                                               <array>
+                                                                       <string>Status</string>
+                                                                       <real>30</real>
+                                                                       <string>FileName</string>
+                                                                       <real>199</real>
+                                                                       <string>Path</string>
+                                                                       <real>197.09500122070312</real>
+                                                               </array>
+                                                               <key>TableFrame</key>
+                                                               <string>{{0, 0}, {452, 250}}</string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXCVSModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>262pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>266pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>SCM</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXCVSModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1C78EAB4065D492600B07095</string>
+                               <string>1C78EAB5065D492600B07095</string>
+                               <string>1C78EAB2065D492600B07095</string>
+                               <string>1CD052920623707200166675</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.scm</string>
+                       <key>WindowString</key>
+                       <string>743 379 452 308 0 0 1280 1002 </string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.breakpoints</string>
+                       <key>IsVertical</key>
+                       <integer>0</integer>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXBottomSmartGroupGIDs</key>
+                                                               <array>
+                                                                       <string>1C77FABC04509CD000000102</string>
+                                                               </array>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CE0B1FE06471DED0097A5F4</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Files</string>
+                                                               <key>PBXProjectStructureProvided</key>
+                                                               <string>no</string>
+                                                               <key>PBXSmartGroupTreeModuleColumnData</key>
+                                                               <dict>
+                                                                       <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+                                                                       <array>
+                                                                               <real>168</real>
+                                                                       </array>
+                                                                       <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+                                                                       <array>
+                                                                               <string>MainColumn</string>
+                                                                       </array>
+                                                               </dict>
+                                                               <key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+                                                               <dict>
+                                                                       <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+                                                                       <array>
+                                                                               <string>1C77FABC04509CD000000102</string>
+                                                                       </array>
+                                                                       <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+                                                                       <array>
+                                                                               <array>
+                                                                                       <integer>0</integer>
+                                                                               </array>
+                                                                       </array>
+                                                                       <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+                                                                       <string>{{0, 0}, {168, 350}}</string>
+                                                               </dict>
+                                                               <key>PBXTopSmartGroupGIDs</key>
+                                                               <array/>
+                                                               <key>XCIncludePerspectivesSwitch</key>
+                                                               <integer>0</integer>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {185, 368}}</string>
+                                                               <key>GroupTreeTableConfiguration</key>
+                                                               <array>
+                                                                       <string>MainColumn</string>
+                                                                       <real>168</real>
+                                                               </array>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>315 424 744 409 0 0 1440 878 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXSmartGroupTreeModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>185pt</string>
+                                               </dict>
+                                               <dict>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CA1AED706398EBD00589147</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Detail</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{{190, 0}, {554, 368}}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>315 424 744 409 0 0 1440 878 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>XCDetailModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>554pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>368pt</string>
+                               </dict>
+                       </array>
+                       <key>MajorVersion</key>
+                       <integer>3</integer>
+                       <key>MinorVersion</key>
+                       <integer>0</integer>
+                       <key>Name</key>
+                       <string>Breakpoints</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXSmartGroupTreeModule</string>
+                               <string>XCDetailModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1CDDB66807F98D9800BB5817</string>
+                               <string>1CDDB66907F98D9800BB5817</string>
+                               <string>1CE0B1FE06471DED0097A5F4</string>
+                               <string>1CA1AED706398EBD00589147</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.breakpointsV3</string>
+                       <key>WindowString</key>
+                       <string>315 424 744 409 0 0 1440 878 </string>
+                       <key>WindowToolGUID</key>
+                       <string>1CDDB66807F98D9800BB5817</string>
+                       <key>WindowToolIsVisible</key>
+                       <integer>1</integer>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.debugAnimator</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Module</key>
+                                                       <string>PBXNavigatorGroup</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Debug Visualizer</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXNavigatorGroup</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>1</integer>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.debugAnimatorV3</string>
+                       <key>WindowString</key>
+                       <string>100 100 700 500 0 0 1280 1002 </string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.bookmarks</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Module</key>
+                                                       <string>PBXBookmarksModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Bookmarks</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXBookmarksModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>0</integer>
+                       <key>WindowString</key>
+                       <string>538 42 401 187 0 0 1280 1002 </string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.projectFormatConflicts</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>Module</key>
+                                                       <string>XCProjectFormatConflictsModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Project Format Conflicts</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>XCProjectFormatConflictsModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>0</integer>
+                       <key>WindowContentMinSize</key>
+                       <string>450 300</string>
+                       <key>WindowString</key>
+                       <string>50 850 472 307 0 0 1440 877</string>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.classBrowser</string>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>ContentConfiguration</key>
+                                                       <dict>
+                                                               <key>OptionsSetName</key>
+                                                               <string>Hierarchy, all classes</string>
+                                                               <key>PBXProjectModuleGUID</key>
+                                                               <string>1CA6456E063B45B4001379D8</string>
+                                                               <key>PBXProjectModuleLabel</key>
+                                                               <string>Class Browser - NSObject</string>
+                                                       </dict>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>ClassesFrame</key>
+                                                               <string>{{0, 0}, {374, 96}}</string>
+                                                               <key>ClassesTreeTableConfiguration</key>
+                                                               <array>
+                                                                       <string>PBXClassNameColumnIdentifier</string>
+                                                                       <real>208</real>
+                                                                       <string>PBXClassBookColumnIdentifier</string>
+                                                                       <real>22</real>
+                                                               </array>
+                                                               <key>Frame</key>
+                                                               <string>{{0, 0}, {630, 331}}</string>
+                                                               <key>MembersFrame</key>
+                                                               <string>{{0, 105}, {374, 395}}</string>
+                                                               <key>MembersTreeTableConfiguration</key>
+                                                               <array>
+                                                                       <string>PBXMemberTypeIconColumnIdentifier</string>
+                                                                       <real>22</real>
+                                                                       <string>PBXMemberNameColumnIdentifier</string>
+                                                                       <real>216</real>
+                                                                       <string>PBXMemberTypeColumnIdentifier</string>
+                                                                       <real>97</real>
+                                                                       <string>PBXMemberBookColumnIdentifier</string>
+                                                                       <real>22</real>
+                                                               </array>
+                                                               <key>PBXModuleWindowStatusBarHidden2</key>
+                                                               <integer>1</integer>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>385 179 630 352 0 0 1440 878 </string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>PBXClassBrowserModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>332pt</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>332pt</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Class Browser</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>PBXClassBrowserModule</string>
+                       </array>
+                       <key>StatusbarIsVisible</key>
+                       <integer>0</integer>
+                       <key>TableOfContents</key>
+                       <array>
+                               <string>1C0AD2AF069F1E9B00FABCE6</string>
+                               <string>1C0AD2B0069F1E9B00FABCE6</string>
+                               <string>1CA6456E063B45B4001379D8</string>
+                       </array>
+                       <key>ToolbarConfiguration</key>
+                       <string>xcode.toolbar.config.classbrowser</string>
+                       <key>WindowString</key>
+                       <string>385 179 630 352 0 0 1440 878 </string>
+                       <key>WindowToolGUID</key>
+                       <string>1C0AD2AF069F1E9B00FABCE6</string>
+                       <key>WindowToolIsVisible</key>
+                       <integer>0</integer>
+               </dict>
+               <dict>
+                       <key>Identifier</key>
+                       <string>windowTool.refactoring</string>
+                       <key>IncludeInToolsMenu</key>
+                       <integer>0</integer>
+                       <key>Layout</key>
+                       <array>
+                               <dict>
+                                       <key>Dock</key>
+                                       <array>
+                                               <dict>
+                                                       <key>BecomeActive</key>
+                                                       <integer>1</integer>
+                                                       <key>GeometryConfiguration</key>
+                                                       <dict>
+                                                               <key>Frame</key>
+                                                               <string>{0, 0}, {500, 335}</string>
+                                                               <key>RubberWindowFrame</key>
+                                                               <string>{0, 0}, {500, 335}</string>
+                                                       </dict>
+                                                       <key>Module</key>
+                                                       <string>XCRefactoringModule</string>
+                                                       <key>Proportion</key>
+                                                       <string>100%</string>
+                                               </dict>
+                                       </array>
+                                       <key>Proportion</key>
+                                       <string>100%</string>
+                               </dict>
+                       </array>
+                       <key>Name</key>
+                       <string>Refactoring</string>
+                       <key>ServiceClasses</key>
+                       <array>
+                               <string>XCRefactoringModule</string>
+                       </array>
+                       <key>WindowString</key>
+                       <string>200 200 500 356 0 0 1920 1200 </string>
+               </dict>
+       </array>
+</dict>
+</plist>
diff --git a/dyld.xcodeproj/kledzik.pbxuser b/dyld.xcodeproj/kledzik.pbxuser
new file mode 100644 (file)
index 0000000..ad6f46d
--- /dev/null
@@ -0,0 +1,140 @@
+// !$*UTF8*$!
+{
+       F93937310A94FAF700070A07 /* update_dyld_shared_cache */ = {
+               activeExec = 0;
+               executables = (
+                       F9DBB2860CD7F5CF009A2B25 /* update_dyld_shared_cache */,
+               );
+       };
+       F9DBB2850CD7F5CF009A2B25 /* dyld */ = {
+               isa = PBXExecutable;
+               activeArgIndices = (
+               );
+               argumentStrings = (
+               );
+               autoAttachOnCrash = 1;
+               breakpointsEnabled = 1;
+               configStateDict = {
+               };
+               customDataFormattersEnabled = 1;
+               debuggerPlugin = GDBDebugging;
+               disassemblyDisplayState = 0;
+               enableDebugStr = 1;
+               environmentEntries = (
+               );
+               executableSystemSymbolLevel = 0;
+               executableUserSymbolLevel = 0;
+               libgmallocEnabled = 0;
+               name = dyld;
+               sourceDirectories = (
+               );
+       };
+       F9DBB2860CD7F5CF009A2B25 /* update_dyld_shared_cache */ = {
+               isa = PBXExecutable;
+               activeArgIndices = (
+               );
+               argumentStrings = (
+               );
+               autoAttachOnCrash = 1;
+               breakpointsEnabled = 1;
+               configStateDict = {
+               };
+               customDataFormattersEnabled = 1;
+               debuggerPlugin = GDBDebugging;
+               disassemblyDisplayState = 0;
+               enableDebugStr = 1;
+               environmentEntries = (
+               );
+               executableSystemSymbolLevel = 0;
+               executableUserSymbolLevel = 0;
+               libgmallocEnabled = 0;
+               name = update_dyld_shared_cache;
+               sourceDirectories = (
+               );
+       };
+       F9DBB2890CD7F5D3009A2B25 /* Source Control */ = {
+               isa = PBXSourceControlManager;
+               fallbackIsa = XCSourceControlManager;
+               isSCMEnabled = 0;
+               scmConfiguration = {
+               };
+       };
+       F9DBB28A0CD7F5D3009A2B25 /* Code sense */ = {
+               isa = PBXCodeSenseManager;
+               indexTemplatePath = "";
+       };
+       F9ED4C8B0630A72300DF4E74 /* Project object */ = {
+               activeArchitecture = i386;
+               activeBuildConfigurationName = Release;
+               activeExecutable = F9DBB2850CD7F5CF009A2B25 /* dyld */;
+               activeTarget = F9ED4C920630A73900DF4E74 /* all */;
+               codeSenseManager = F9DBB28A0CD7F5D3009A2B25 /* Code sense */;
+               executables = (
+                       F9DBB2850CD7F5CF009A2B25 /* dyld */,
+                       F9DBB2860CD7F5CF009A2B25 /* update_dyld_shared_cache */,
+               );
+               perUserDictionary = {
+                       PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
+                               PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+                               PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+                               PBXFileTableDataSourceColumnWidthsKey = (
+                                       20,
+                                       243,
+                                       20,
+                                       48.16259765625,
+                                       43,
+                                       43,
+                                       20,
+                               );
+                               PBXFileTableDataSourceColumnsKey = (
+                                       PBXFileDataSource_FiletypeID,
+                                       PBXFileDataSource_Filename_ColumnID,
+                                       PBXFileDataSource_Built_ColumnID,
+                                       PBXFileDataSource_ObjectSize_ColumnID,
+                                       PBXFileDataSource_Errors_ColumnID,
+                                       PBXFileDataSource_Warnings_ColumnID,
+                                       PBXFileDataSource_Target_ColumnID,
+                               );
+                       };
+                       PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
+                               PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+                               PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+                               PBXFileTableDataSourceColumnWidthsKey = (
+                                       20,
+                                       203,
+                                       60,
+                                       20,
+                                       48.16259765625,
+                                       43,
+                                       43,
+                               );
+                               PBXFileTableDataSourceColumnsKey = (
+                                       PBXFileDataSource_FiletypeID,
+                                       PBXFileDataSource_Filename_ColumnID,
+                                       PBXTargetDataSource_PrimaryAttribute,
+                                       PBXFileDataSource_Built_ColumnID,
+                                       PBXFileDataSource_ObjectSize_ColumnID,
+                                       PBXFileDataSource_Errors_ColumnID,
+                                       PBXFileDataSource_Warnings_ColumnID,
+                               );
+                       };
+                       PBXPerProjectTemplateStateSaveDate = 215479759;
+                       PBXWorkspaceStateSaveDate = 215479759;
+               };
+               sourceControlManager = F9DBB2890CD7F5D3009A2B25 /* Source Control */;
+               userBuildSettings = {
+               };
+       };
+       F9ED4C920630A73900DF4E74 /* all */ = {
+               activeExec = 0;
+       };
+       F9ED4C970630A76000DF4E74 /* dyld */ = {
+               activeExec = 0;
+               executables = (
+                       F9DBB2850CD7F5CF009A2B25 /* dyld */,
+               );
+       };
+       F9ED4C9E0630A76B00DF4E74 /* libdyld */ = {
+               activeExec = 0;
+       };
+}
index a10989e9aca1e26594b911ae3277f861333cd11b..ab2b56e59c8fd03e23d6896bd9b8516fd5f0200b 100644 (file)
                        buildConfigurationList = F9D8C7E5087B087300E93EFB /* Build configuration list for PBXAggregateTarget "all" */;
                        buildPhases = (
                        );
-                       buildSettings = {
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = all;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
-                       };
                        dependencies = (
                                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */,
                                F9ED4CA90630A78A00DF4E74 /* PBXTargetDependency */,
+                               F93937380A94FB6A00070A07 /* PBXTargetDependency */,
                        );
                        name = all;
                        productName = all;
                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 */; };
-               EF79A017070D295200F78484 /* NSModule.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FF1070D27BB00F78484 /* NSModule.3 */; };
-               EF79A018070D295200F78484 /* NSObjectFileImage.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FF2070D27BB00F78484 /* NSObjectFileImage.3 */; };
-               EF79A019070D295200F78484 /* NSObjectFileImage_priv.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FF3070D27BB00F78484 /* NSObjectFileImage_priv.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 */; };
-               F939F21A078F1A2100AC144F /* dyld_debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F939F219078F1A2100AC144F /* dyld_debug.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 */; };
+               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"; }; };
+               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 */; };
                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 */; };
@@ -64,7 +59,6 @@
                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 */; };
-               F9FE429C06C82066001D8CE5 /* dyldLibSystemThreadHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = F9FE429B06C82066001D8CE5 /* dyldLibSystemThreadHelpers.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
                };
 /* End PBXBuildRule section */
 
-/* Begin PBXBuildStyle section */
-               F9ED4C890630A72300DF4E74 /* Development */ = {
-                       isa = PBXBuildStyle;
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               DEAD_CODE_STRIPPING = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                       };
-                       name = Development;
+/* Begin PBXContainerItemProxy section */
+               F93937370A94FB6A00070A07 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F93937310A94FAF700070A07;
+                       remoteInfo = update_dyld_shared_cache;
                };
-               F9ED4C8A0630A72300DF4E74 /* Deployment */ = {
-                       isa = PBXBuildStyle;
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               GCC_ENABLE_CPP_RTTI = NO;
-                       };
-                       name = Deployment;
+               F93937390A94FB6E00070A07 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F93937310A94FAF700070A07;
+                       remoteInfo = update_dyld_shared_cache;
                };
-/* End PBXBuildStyle section */
-
-/* Begin PBXContainerItemProxy section */
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
+               F932C2560BC32AC30018B20D /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /System/Library/LaunchDaemons;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               F932C2520BC32ABB0018B20D /* com.apple.dyld.plist in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                F93AA9B30630AE8200301D9F /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        files = (
                                F939F21B078F1A2C00AC144F /* dyld_debug.h in CopyFiles */,
                                F93AA9A50630AE1E00301D9F /* dyld.h in CopyFiles */,
+                               F98D274D0AA79D7400416316 /* dyld_images.h in CopyFiles */,
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        dstPath = "/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
+                               F919ECB1090455AB002331E3 /* dyld-update-prebinding.h in CopyFiles */,
                                F93AA9A30630AE1E00301D9F /* dyld_gdb.h in CopyFiles */,
                                F93AA9A40630AE1E00301D9F /* dyld_priv.h in CopyFiles */,
                        );
                                EF79A014070D295200F78484 /* dlopen.3 in CopyFiles */,
                                EF79A015070D295200F78484 /* dlsym.3 in CopyFiles */,
                                EF79A016070D295200F78484 /* dyld.3 in CopyFiles */,
-                               EF79A017070D295200F78484 /* NSModule.3 in CopyFiles */,
-                               EF79A018070D295200F78484 /* NSObjectFileImage.3 in CopyFiles */,
-                               EF79A019070D295200F78484 /* NSObjectFileImage_priv.3 in CopyFiles */,
+                               F9E572020A66EF4A007D9BE9 /* dlopen_preflight.3 in CopyFiles */,
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               F9D238DD0A9E2FEE002B55C7 /* CopyFiles */ = {
+                       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 */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
                EF799FEE070D27BB00F78484 /* dlopen.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dlopen.3; path = doc/man/man3/dlopen.3; sourceTree = SOURCE_ROOT; };
                EF799FEF070D27BB00F78484 /* dlsym.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dlsym.3; path = doc/man/man3/dlsym.3; sourceTree = SOURCE_ROOT; };
                EF799FF0070D27BB00F78484 /* dyld.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dyld.3; path = doc/man/man3/dyld.3; sourceTree = SOURCE_ROOT; };
-               EF799FF1070D27BB00F78484 /* NSModule.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = NSModule.3; path = doc/man/man3/NSModule.3; sourceTree = SOURCE_ROOT; };
-               EF799FF2070D27BB00F78484 /* NSObjectFileImage.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = NSObjectFileImage.3; path = doc/man/man3/NSObjectFileImage.3; sourceTree = SOURCE_ROOT; };
-               EF799FF3070D27BB00F78484 /* NSObjectFileImage_priv.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = NSObjectFileImage_priv.3; path = doc/man/man3/NSObjectFileImage_priv.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>"; };
+               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>"; };
+               F93937400A94FC4700070A07 /* dyld_cache_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dyld_cache_format.h; sourceTree = "<group>"; };
+               F93937410A94FC4700070A07 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = FileAbstraction.hpp; sourceTree = "<group>"; };
+               F93937430A94FC4700070A07 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOFileAbstraction.hpp; sourceTree = "<group>"; };
+               F93937440A94FC4700070A07 /* MachOLayout.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOLayout.hpp; sourceTree = "<group>"; };
+               F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = update_dyld_shared_cache.cpp; sourceTree = "<group>"; };
                F939F219078F1A2100AC144F /* dyld_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_debug.h; path = "include/mach-o/dyld_debug.h"; sourceTree = "<group>"; };
+               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>"; };
+               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; };
+               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; };
-               F9ED4C980630A76000DF4E74 /* dyld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylinker"; includeInIndex = 0; path = dyld; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; path = update_dyld_shared_cache.1; sourceTree = "<group>"; };
+               F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = dlopen_preflight.3; sourceTree = "<group>"; };
+               F9ED4C980630A76000DF4E74 /* dyld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyld; sourceTree = BUILT_PRODUCTS_DIR; };
                F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdyldapis.a; sourceTree = BUILT_PRODUCTS_DIR; };
                F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld_gdb.cpp; path = src/dyld_gdb.cpp; sourceTree = SOURCE_ROOT; };
                F9ED4CC70630A7F100DF4E74 /* dyld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld.cpp; path = src/dyld.cpp; sourceTree = SOURCE_ROOT; };
                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; };
-               F9FE429B06C82066001D8CE5 /* dyldLibSystemThreadHelpers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyldLibSystemThreadHelpers.h; path = src/dyldLibSystemThreadHelpers.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-               F9ED4C960630A76000DF4E74 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F9ED4C9D0630A76B00DF4E74 /* Frameworks */ = {
+               F93937300A94FAF700070A07 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXGroup;
                        children = (
                                EF799FE9070D27BB00F78484 /* dyld.1 */,
+                               F93C8C290B84EBFC00615A00 /* update_prebinding.1 */,
+                               F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */,
                        );
                        name = man1;
                        path = doc/man/man1;
                                EF799FED070D27BB00F78484 /* dlerror.3 */,
                                EF799FEE070D27BB00F78484 /* dlopen.3 */,
                                EF799FEF070D27BB00F78484 /* dlsym.3 */,
+                               F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */,
                                EF799FF0070D27BB00F78484 /* dyld.3 */,
-                               EF799FF1070D27BB00F78484 /* NSModule.3 */,
-                               EF799FF2070D27BB00F78484 /* NSObjectFileImage.3 */,
-                               EF799FF3070D27BB00F78484 /* NSObjectFileImage_priv.3 */,
                        );
                        name = man3;
                        path = doc/man/man3;
                        sourceTree = SOURCE_ROOT;
                };
+               F939373D0A94FC4700070A07 /* launch-cache */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F939373E0A94FC4700070A07 /* Architectures.hpp */,
+                               F939373F0A94FC4700070A07 /* CacheFileAbstraction.hpp */,
+                               F93937400A94FC4700070A07 /* dyld_cache_format.h */,
+                               F93937410A94FC4700070A07 /* FileAbstraction.hpp */,
+                               F93937430A94FC4700070A07 /* MachOFileAbstraction.hpp */,
+                               F93937440A94FC4700070A07 /* MachOLayout.hpp */,
+                               F98935BA0A9A412B00FB6228 /* MachORebaser.hpp */,
+                               F98935B90A9A412B00FB6228 /* MachOBinder.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 */,
+                       );
+                       path = "launch-cache";
+                       sourceTree = "<group>";
+               };
                F9ED4C870630A72200DF4E74 = {
                        isa = PBXGroup;
                        children = (
                                F9ED4CC30630A7BE00DF4E74 /* doc */,
                                F9ED4CBE0630A7B100DF4E74 /* include */,
                                F9ED4C990630A76000DF4E74 /* Products */,
+                               F939373D0A94FC4700070A07 /* launch-cache */,
                        );
                        sourceTree = "<group>";
                };
                        children = (
                                F9ED4C980630A76000DF4E74 /* dyld */,
                                F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */,
+                               F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */,
                                F9ED4CC70630A7F100DF4E74 /* dyld.cpp */,
                                F9ED4CC80630A7F100DF4E74 /* dyld.h */,
-                               F9FE429B06C82066001D8CE5 /* dyldLibSystemThreadHelpers.h */,
                                F9ED4CC90630A7F100DF4E74 /* dyldAPIs.cpp */,
                                F9ED4CCA0630A7F100DF4E74 /* dyldExceptions.c */,
+                               F9AB709D0BA75730002F6068 /* dyldLibSystemInterface.h */,
                                F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */,
                                F9ED4CCB0630A7F100DF4E74 /* dyldInitialization.cpp */,
                                F9ED4CCC0630A7F100DF4E74 /* dyldLock.cpp */,
                                F9ED4CD20630A7F100DF4E74 /* ImageLoader.h */,
                                F9ED4CD30630A7F100DF4E74 /* ImageLoaderMachO.cpp */,
                                F9ED4CD40630A7F100DF4E74 /* ImageLoaderMachO.h */,
+                               F973667C0BD004F200E5E1B4 /* ImageLoaderPE.cpp */,
+                               F973667D0BD004F200E5E1B4 /* ImageLoaderPE.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 */,
                                F906E2230639E96400B13DB2 /* dyld_debug.c */,
                        );
                        name = src;
                F9ED4CBE0630A7B100DF4E74 /* include */ = {
                        isa = PBXGroup;
                        children = (
+                               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 */,
                };
 /* End PBXGroup section */
 
-/* Begin PBXHeadersBuildPhase section */
-               F9ED4C9B0630A76B00DF4E74 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               F9FE429C06C82066001D8CE5 /* dyldLibSystemThreadHelpers.h in Headers */,
-                               F939F21A078F1A2100AC144F /* dyld_debug.h in Headers */,
+/* Begin PBXNativeTarget section */
+               F93937310A94FAF700070A07 /* update_dyld_shared_cache */ = {
+                       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 */,
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = update_dyld_shared_cache;
+                       productName = update_dyld_shared_cache;
+                       productReference = F93937320A94FAF700070A07 /* update_dyld_shared_cache */;
+                       productType = "com.apple.product-type.tool";
                };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
                F9ED4C970630A76000DF4E74 /* dyld */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */;
                        buildPhases = (
                                F9ED4C950630A76000DF4E74 /* Sources */,
-                               F9ED4C960630A76000DF4E74 /* Frameworks */,
                        );
                        buildRules = (
                                F921D318070376B0000D1056 /* PBXBuildRule */,
                                F921D317070376A6000D1056 /* PBXBuildRule */,
                                F921D3160703769A000D1056 /* PBXBuildRule */,
                        );
-                       buildSettings = {
-                               ARCHS = ppc;
-                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
-                               DEAD_CODE_STRIPPING = YES;
-                               EXPORTED_SYMBOLS_FILE = "";
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_CPP_RTTI = NO;
-                               GCC_MODEL_TUNING = G4;
-                               GCC_OPTIMIZATION_LEVEL = 3;
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/lib;
-                               LIBRARY_SEARCH_PATHS = "";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = (
-                                       "-v",
-                                       "-seg1addr",
-                                       8fe00000,
-                                       "-exported_symbols_list",
-                                       src/dyld.exp,
-                                       "-nostdlib",
-                                       "-lstdc++",
-                                       /usr/local/lib/system/libc.a,
-                                       "-lgcc",
-                                       "-Wl,-e,__dyld_start",
-                                       "-Wl,-dylinker",
-                                       "-Wl,-dylinker_install_name,/usr/lib/dyld",
-                               );
-                               OTHER_REZFLAGS = "";
-                               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",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
-                       };
                        dependencies = (
+                               F939373A0A94FB6E00070A07 /* PBXTargetDependency */,
                        );
                        name = dyld;
                        productName = dyld;
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */;
                        buildPhases = (
+                               F9AC7E7E0B7BB3D300FEB38B /* ShellScript */,
+                               F9AB70540BA73985002F6068 /* ShellScript */,
                                F9ED4C9C0630A76B00DF4E74 /* Sources */,
-                               F9ED4C9B0630A76B00DF4E74 /* Headers */,
                                F93AA9B30630AE8200301D9F /* CopyFiles */,
                                F9574CB206C95C0D00142BFA /* CopyFiles */,
                                F93AA9B60630AEB100301D9F /* CopyFiles */,
                                F93AA9C20630AF0700301D9F /* CopyFiles */,
                                F93AA9C60630AF1F00301D9F /* CopyFiles */,
-                               F9CA205D06CBF578000BA084 /* ShellScript */,
-                               F9ED4C9D0630A76B00DF4E74 /* Frameworks */,
+                               F918692408B16F6900E0F9DB /* ShellScript */,
                        );
                        buildRules = (
                                F921D31E070376F1000D1056 /* PBXBuildRule */,
                                F9574C4906C94DA700142BFA /* PBXBuildRule */,
                        );
-                       buildSettings = {
-                               ARCHS = ppc;
-                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/local/lib/system;
-                               LIBRARY_STYLE = STATIC;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = dyldapis;
-                               SECTORDER_FLAGS = "";
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
-                       };
                        dependencies = (
                        );
                        name = libdyld;
                F9ED4C8B0630A72300DF4E74 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */;
-                       buildSettings = {
-                       };
-                       buildStyles = (
-                               F9ED4C890630A72300DF4E74 /* Development */,
-                               F9ED4C8A0630A72300DF4E74 /* Deployment */,
-                       );
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = F9ED4C870630A72200DF4E74;
                        productRefGroup = F9ED4C990630A76000DF4E74 /* Products */;
                        projectDirPath = "";
+                       projectRoot = "";
                        targets = (
                                F9ED4C920630A73900DF4E74 /* all */,
                                F9ED4C970630A76000DF4E74 /* dyld */,
                                F9ED4C9E0630A76B00DF4E74 /* libdyld */,
+                               F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               F9CA205D06CBF578000BA084 /* ShellScript */ = {
+               F918692408B16F6900E0F9DB /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
-                               "${DSTROOT}/usr/local/lib/system/ldyldapis.a",
                        );
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "cd ${DSTROOT}/usr/local/lib/system\nln -s libdyldapis.a libdyldapis_profile.a\nln -s libdyldapis.a libdyldapis_debug.a\n";
+                       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 */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                               "$(BUILT_PRODUCTS_DIR)/version.c",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "/Developer/Makefiles/bin/version.pl ${ProjectName} > ${BUILT_PRODUCTS_DIR}/version.c\n";
+                       showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+               F939372F0A94FAF700070A07 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F93937470A94FC4700070A07 /* update_dyld_shared_cache.cpp in Sources */,
+                               F93075C30BA1FE4D004BCA09 /* dyld_shared_cache_server.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                F9ED4C950630A76000DF4E74 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                                F9ED4CDF0630A7F100DF4E74 /* dyldStartup.s in Sources */,
-                               F9ED4CD60630A7F100DF4E74 /* dyld_gdb.cpp in Sources */,
+                               F9ED4CDB0630A7F100DF4E74 /* dyldInitialization.cpp in Sources */,
                                F9ED4CD70630A7F100DF4E74 /* dyld.cpp in Sources */,
                                F9ED4CD90630A7F100DF4E74 /* dyldAPIs.cpp in Sources */,
                                F9ED4CDA0630A7F100DF4E74 /* dyldExceptions.c in Sources */,
-                               F9ED4CDB0630A7F100DF4E74 /* dyldInitialization.cpp in Sources */,
-                               F9ED4CDE0630A7F100DF4E74 /* dyldNew.cpp in Sources */,
+                               F9ED4CD60630A7F100DF4E74 /* dyld_gdb.cpp in Sources */,
                                F9ED4CE00630A7F100DF4E74 /* glue.c in Sources */,
                                F9ED4CE10630A7F100DF4E74 /* ImageLoader.cpp in Sources */,
                                F9ED4CE30630A7F100DF4E74 /* ImageLoaderMachO.cpp in Sources */,
                                F9ED4CE50630A7F100DF4E74 /* stub_binding_helper.s in Sources */,
+                               F9ED4CDE0630A7F100DF4E74 /* dyldNew.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                F9F256360639DBCC00A7427D /* dyldLock.cpp in Sources */,
                                F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */,
                                F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
+                               F9AC7E940B7BB67700FEB38B /* version.c in Sources */,
+                               F9AB705B0BA73A11002F6068 /* dyld_shared_cache_user.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+               F93937380A94FB6A00070A07 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
+                       targetProxy = F93937370A94FB6A00070A07 /* PBXContainerItemProxy */;
+               };
+               F939373A0A94FB6E00070A07 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
+                       targetProxy = F93937390A94FB6E00070A07 /* PBXContainerItemProxy */;
+               };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F9ED4C970630A76000DF4E74 /* dyld */;
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
-               F9D8C7DE087B087300E93EFB /* Development */ = {
+               F93937350A94FB2900070A07 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
-                               DEAD_CODE_STRIPPING = NO;
-                               EXPORTED_SYMBOLS_FILE = "";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_CPP_RTTI = NO;
-                               GCC_MODEL_TUNING = G4;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/lib;
-                               LIBRARY_SEARCH_PATHS = "";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS_i386 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc64 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_x86_64 = "-lstdc++-static  -seg1addr 0x7fff5fc00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_REZFLAGS = "";
-                               PER_ARCH_CFLAGS_ppc = "";
-                               PER_ARCH_CFLAGS_ppc64 = "-msoft-float";
+                               GCC_THREADSAFE_STATICS = NO;
+                               GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+                               GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+                               GCC_WARN_MISSING_PARENTHESES = YES;
+                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               PRODUCT_NAME = dyld;
-                               STRIPFLAGS = "-S";
-                               UNSTRIPPED_PRODUCT = NO;
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
-                               VERSIONING_SYSTEM = "apple-generic";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
+                               PRODUCT_NAME = update_dyld_shared_cache;
+                               VALID_ARCHS = "ppc i386";
                        };
-                       name = Development;
+                       name = Debug;
                };
-               F9D8C7DF087B087300E93EFB /* Deployment */ = {
+               F93937360A94FB2900070A07 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = ppc;
                                COPY_PHASE_STRIP = YES;
                                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";
+                               VERSIONING_SYSTEM = "apple-generic";
+                       };
+                       name = Release;
+               };
+               F9D8C7DE087B087300E93EFB /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               BASE_ADDRESS_i386 = 0x8f000000;
+                               BASE_ADDRESS_ppc = 0x8f000000;
+                               BASE_ADDRESS_ppc64 = 0x7fff5fc00000;
+                               BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
-                               EXPORTED_SYMBOLS_FILE = "";
+                               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";
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_CPP_RTTI = NO;
                                GCC_MODEL_TUNING = G4;
-                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               HEADER_SEARCH_PATHS = ./include;
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+                               GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+                               GCC_WARN_MISSING_PARENTHESES = YES;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = NO;
+                               HEADER_SEARCH_PATHS = (
+                                       ./include,
+                                       "./launch-cache",
+                               );
                                INSTALL_PATH = /usr/lib;
-                               LIBRARY_SEARCH_PATHS = "";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS_i386 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc64 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_x86_64 = "-lstdc++-static  -seg1addr 0x7fff5fc00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_REZFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-seg1addr",
+                                       "$(BASE_ADDRESS_$(CURRENT_ARCH))",
+                                       "-lstdc++-static",
+                                       "-nostdlib",
+                                       /usr/local/lib/system/libc.a,
+                                       "-lgcc_eh",
+                                       "-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;
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
                                );
                        };
-                       name = Deployment;
+                       name = Debug;
                };
-               F9D8C7E0087B087300E93EFB /* Default */ = {
+               F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = ppc;
+                               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 = "$(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";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_MODEL_TUNING = G4;
                                GCC_OPTIMIZATION_LEVEL = 3;
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               HEADER_SEARCH_PATHS = ./include;
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       ./include,
+                                       "./launch-cache",
+                               );
                                INSTALL_PATH = /usr/lib;
-                               LIBRARY_SEARCH_PATHS = "";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS_i386 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_ppc64 = "-lstdc++-static  -seg1addr 8fe00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_LDFLAGS_x86_64 = "-lstdc++-static  -seg1addr 0x7fff5fc00000 -exported_symbols_list src/dyld64.exp -nostdlib /usr/local/lib/system/libc.a -lgcc_eh -lgcc -Wl,-e,__dyld_start -Wl,-dylinker -Wl,-dylinker_install_name,/usr/lib/dyld";
-                               OTHER_REZFLAGS = "";
+                               OTHER_LDFLAGS = (
+                                       "-seg1addr",
+                                       "$(BASE_ADDRESS_$(CURRENT_ARCH))",
+                                       "-lstdc++-static",
+                                       "-nostdlib",
+                                       /usr/local/lib/system/libc.a,
+                                       "-lgcc_eh",
+                                       "-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;
                                        "-Wno-unknown-pragmas",
                                );
                        };
-                       name = Default;
+                       name = Release;
                };
-               F9D8C7E2087B087300E93EFB /* Development */ = {
+               F9D8C7E2087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = ppc;
-                               COPY_PHASE_STRIP = NO;
-                               DEAD_CODE_STRIPPING = NO;
+                               ARCHS = "$(NATIVE_ARCH_ACTUAL)";
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_ENABLE_CPP_RTTI = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                HEADER_SEARCH_PATHS = ./include;
                                INSTALL_PATH = /usr/local/lib/system;
                                LIBRARY_STYLE = STATIC;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
                                PRODUCT_NAME = dyldapis;
-                               SECTORDER_FLAGS = "";
                                VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-unknown-pragmas",
                                );
                        };
-                       name = Development;
+                       name = Debug;
                };
-               F9D8C7E3087B087300E93EFB /* Deployment */ = {
+               F9D8C7E4087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = ppc;
-                               COPY_PHASE_STRIP = YES;
+                               COPY_PHASE_STRIP = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
                                HEADER_SEARCH_PATHS = ./include;
                                INSTALL_PATH = /usr/local/lib/system;
                                LIBRARY_STYLE = STATIC;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = dyldapis;
-                               SECTORDER_FLAGS = "";
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
-                       };
-                       name = Deployment;
-               };
-               F9D8C7E4087B087300E93EFB /* Default */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ARCHS = ppc;
-                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/local/lib/system;
-                               LIBRARY_STYLE = STATIC;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
                                PRODUCT_NAME = dyldapis;
-                               SECTORDER_FLAGS = "";
                                VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-unknown-pragmas",
                                );
                        };
-                       name = Default;
+                       name = Release;
                };
-               F9D8C7E6087B087300E93EFB /* Development */ = {
+               F9D8C7E6087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               DEAD_CODE_STRIPPING = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
                                PRODUCT_NAME = all;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
                        };
-                       name = Development;
+                       name = Debug;
                };
-               F9D8C7E7087B087300E93EFB /* Deployment */ = {
+               F9D8C7E8087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               GCC_ENABLE_CPP_RTTI = NO;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
                                PRODUCT_NAME = all;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
                        };
-                       name = Deployment;
+                       name = Release;
                };
-               F9D8C7E8087B087300E93EFB /* Default */ = {
+               F9D8C7EA087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PRODUCT_NAME = all;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = (
-                                       "-Wmost",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
                        };
-                       name = Default;
+                       name = Debug;
                };
-               F9D8C7EA087B087300E93EFB /* Development */ = {
+               F9D8C7EC087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
-                       name = Development;
-               };
-               F9D8C7EB087B087300E93EFB /* Deployment */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                       };
-                       name = Deployment;
-               };
-               F9D8C7EC087B087300E93EFB /* Default */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                       };
-                       name = Default;
+                       name = Release;
                };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+               F93937340A94FB2900070A07 /* Build configuration list for PBXNativeTarget "update_dyld_shared_cache" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F93937350A94FB2900070A07 /* Debug */,
+                               F93937360A94FB2900070A07 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               F9D8C7DE087B087300E93EFB /* Development */,
-                               F9D8C7DF087B087300E93EFB /* Deployment */,
-                               F9D8C7E0087B087300E93EFB /* Default */,
+                               F9D8C7DE087B087300E93EFB /* Debug */,
+                               F9D8C7E0087B087300E93EFB /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Default;
+                       defaultConfigurationName = Release;
                };
                F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               F9D8C7E2087B087300E93EFB /* Development */,
-                               F9D8C7E3087B087300E93EFB /* Deployment */,
-                               F9D8C7E4087B087300E93EFB /* Default */,
+                               F9D8C7E2087B087300E93EFB /* Debug */,
+                               F9D8C7E4087B087300E93EFB /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Default;
+                       defaultConfigurationName = Release;
                };
                F9D8C7E5087B087300E93EFB /* Build configuration list for PBXAggregateTarget "all" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               F9D8C7E6087B087300E93EFB /* Development */,
-                               F9D8C7E7087B087300E93EFB /* Deployment */,
-                               F9D8C7E8087B087300E93EFB /* Default */,
+                               F9D8C7E6087B087300E93EFB /* Debug */,
+                               F9D8C7E8087B087300E93EFB /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Default;
+                       defaultConfigurationName = Release;
                };
                F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               F9D8C7EA087B087300E93EFB /* Development */,
-                               F9D8C7EB087B087300E93EFB /* Deployment */,
-                               F9D8C7EC087B087300E93EFB /* Default */,
+                               F9D8C7EA087B087300E93EFB /* Debug */,
+                               F9D8C7EC087B087300E93EFB /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Default;
+                       defaultConfigurationName = Release;
                };
 /* End XCConfigurationList section */
        };
index 77d7521ecc7da9531cd432b0a574a435b5bc6d11..2e502c554f560d13111328433d0dba1f963e9a4e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -36,7 +36,9 @@ extern "C" {
 
 #include <sys/cdefs.h>
 
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
+#include <stdbool.h>
+#include <AvailabilityMacros.h>
 /*
  * Structure filled in by dladdr().
  */
@@ -55,20 +57,27 @@ extern char * dlerror(void);
 extern void * dlopen(const char * __path, int __mode);
 extern void * dlsym(void * __handle, const char * __symbol);
 
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
+extern bool dlopen_preflight(const char* __path) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
+#endif /* not POSIX */
+
+
 #define RTLD_LAZY      0x1
 #define RTLD_NOW       0x2
 #define RTLD_LOCAL     0x4
 #define RTLD_GLOBAL    0x8
 
-#ifndef _POSIX_C_SOURCE
+#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
 #define RTLD_NOLOAD    0x10
 #define RTLD_NODELETE  0x80
+#define RTLD_FIRST     0x100   /* Mac OS X 10.5 and later */
 
 /*
  * Special handle arguments for dlsym().
  */
 #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) */
 #endif /* not POSIX */
 
 #ifdef __cplusplus
diff --git a/include/mach-o/dyld-update-prebinding.h b/include/mach-o/dyld-update-prebinding.h
new file mode 100644 (file)
index 0000000..9e09413
--- /dev/null
@@ -0,0 +1,19 @@
+
+#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 62cb9a7ddcf458013a6d3c30a3e03c86a07ce09d..10b7099169fe02ee5e2293bc7ccf008f9268995d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #ifndef _MACH_O_DYLD_H_
 #define _MACH_O_DYLD_H_
 
-#if __cplusplus
-extern "C" {
-#endif /* __cplusplus */
 
 #include <stddef.h>
 #include <stdint.h>
-#if __cplusplus
-  /* C++ has bool type built in */
-#else
- #include <stdbool.h>
-#endif
+#include <stdbool.h>
+
 #include <mach-o/loader.h>
 #include <AvailabilityMacros.h>
 
+#if __cplusplus
+extern "C" {
+#endif 
+
+/*
+ * The following functions allow you to iterate through all loaded images.  
+ * This is not a thread safe operation.  Another thread can add or remove
+ * an image during the iteration.  
+ *
+ * Many uses of these routines can be replace by a call to dladdr() which 
+ * 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;
+
+
+/*
+ * The following functions allow you to install callbacks which will be called   
+ * by dyld whenever an image is loaded or unloaded.  During a call to _dyld_register_func_for_add_image()
+ * the callback func is called for every existing image.  Later, it is called as each new image
+ * is loaded and bound (but initializers not yet run).  The callback registered with
+ * _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;
+
+
+/*
+ * NSVersionOfRunTimeLibrary() returns the current_version number of the currently dylib 
+ * 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;
+
+
+/*
+ * NSVersionOfRunTimeLibrary() returns the current_version number that the main executable was linked
+ * against at build time.  The libraryName parameter would be "bar" for /path/libbar.3.dylib and
+ * "Foo" for /path/Foo.framework/Versions/A/Foo.  It returns -1 if the main executable did not link
+ * against the specified library.
+ */
+extern int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)           AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+
+
+/*
+ * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter
+ * should initially be the size of the buffer.  The function returns 0 if the path was successfully copied.
+ * It returns -1 if the buffer is not large enough, and *bufsize is set to the size required. 
+ * 
+ * Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable. 
+ * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize 
+ * needed could be more than MAXPATHLEN.
+ */
+extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
+
+
+
+/*
+ * _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;
+
+
+
+
+
+/*
+ * The following dyld API's are deprecated as of Mac OS X 10.5.  They are either  
+ * no longer necessary or are superceeded by dlopen and friends in <dlfcn.h>.
+ * dlopen/dlsym/dlclose have been available since Mac OS X 10.3 and work with 
+ * dylibs and bundles.  
+ *
+ *    NSAddImage                           -> dlopen
+ *    NSLookupSymbolInImage                -> dlsym
+ *    NSCreateObjectFileImageFromFile      -> dlopen
+ *    NSDestroyObjectFileImage             -> dlclose
+ *    NSLinkModule                         -> not needed when dlopen used
+ *    NSUnLinkModule                       -> not needed when dlclose used
+ *    NSLookupSymbolInModule               -> dlsym
+ *    _dyld_image_containing_address       -> dladdr
+ *    NSLinkEditError                      -> dlerror
+ *
+ */
+
 #ifndef ENUM_DYLD_BOOL
 #define ENUM_DYLD_BOOL
-#undef FALSE
-#undef TRUE
-enum DYLD_BOOL {
-    FALSE,
-    TRUE
-};
+  #undef FALSE
+  #undef TRUE
+  enum DYLD_BOOL { FALSE, TRUE };
 #endif /* ENUM_DYLD_BOOL */
 
-/*
- * The high level NS... API.
- */
 
 /* Object file image API */
 typedef enum {
@@ -63,119 +141,52 @@ typedef enum {
 
 typedef struct __NSObjectFileImage*  NSObjectFileImage;
 
-/* limited implementation, only MH_BUNDLE files can be used */
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(
-    const char *pathName,
-    NSObjectFileImage *objectFileImage);
-extern NSObjectFileImageReturnCode NSCreateCoreFileImageFromFile(
-    const char *pathName,
-    NSObjectFileImage *objectFileImage);
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(
-    const void *address,
-    size_t size, 
-    NSObjectFileImage *objectFileImage);
-extern bool NSDestroyObjectFileImage(
-    NSObjectFileImage objectFileImage);
-/*
- * API on NSObjectFileImage's for:
- *   "for Each Symbol Definition In Object File Image" (for Dynamic Bundles)
- *   and the same thing for references
- */
-extern uint32_t NSSymbolDefinitionCountInObjectFileImage(
-    NSObjectFileImage objectFileImage);
-extern const char * NSSymbolDefinitionNameInObjectFileImage(
-    NSObjectFileImage objectFileImage,
-    uint32_t ordinal);
-extern uint32_t NSSymbolReferenceCountInObjectFileImage(
-    NSObjectFileImage objectFileImage);
-extern const char * NSSymbolReferenceNameInObjectFileImage(
-    NSObjectFileImage objectFileImage,
-    uint32_t ordinal,
-    bool *tentative_definition); /* can be NULL */
-/*
- * API on NSObjectFileImage:
- *   "does Object File Image define symbol name X" (using sorted symbol table)
- *   and a way to get the named objective-C section
- */
-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); /* can be NULL */
-/* SPI first appeared in Mac OS X 10.3 */
-extern bool NSHasModInitObjectFileImage(
-    NSObjectFileImage objectFileImage)
-    AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
-
-/* module API */
+/* 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;
+
 typedef struct __NSModule* NSModule;
-extern const char * NSNameOfModule(
-    NSModule m); 
-extern const char * NSLibraryNameForModule(
-    NSModule m);
-
-/* limited implementation, only MH_BUNDLE files can be linked */
-extern NSModule NSLinkModule(
-    NSObjectFileImage objectFileImage, 
-    const char *moduleName,
-    uint32_t options);
-#define NSLINKMODULE_OPTION_NONE               0x0
-#define NSLINKMODULE_OPTION_BINDNOW            0x1
-#define NSLINKMODULE_OPTION_PRIVATE            0x2
-#define NSLINKMODULE_OPTION_RETURN_ON_ERROR    0x4
-#define NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES 0x8
-#define NSLINKMODULE_OPTION_TRAILING_PHYS_NAME 0x10
-
-/* limited implementation, only modules loaded with NSLinkModule() can be
-   unlinked */
-extern bool NSUnLinkModule(
-    NSModule module, 
-    uint32_t options);
-#define NSUNLINKMODULE_OPTION_NONE                     0x0
-#define NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED       0x1
+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 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;
+#define NSLINKMODULE_OPTION_NONE                         0x0
+#define NSLINKMODULE_OPTION_BINDNOW                      0x1
+#define NSLINKMODULE_OPTION_PRIVATE                      0x2
+#define NSLINKMODULE_OPTION_RETURN_ON_ERROR              0x4
+#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;
+#define NSUNLINKMODULE_OPTION_NONE                  0x0
+#define NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED    0x1
 #define NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES    0x2
 
-/* not yet implemented */
-extern NSModule NSReplaceModule(
-    NSModule moduleToReplace,
-    NSObjectFileImage newObjectFileImage, 
-    uint32_t options);
-
 /* 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);
-extern NSSymbol NSLookupSymbolInImage(
-    const struct mach_header *image,
-    const char *symbolName,
-    uint32_t options);
+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;
 #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);
-extern void * NSAddressOfSymbol(
-    NSSymbol symbol);
-extern NSModule NSModuleForSymbol(
-    NSSymbol symbol);
+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;
 
 /* error handling API */
 typedef enum {
@@ -203,119 +214,41 @@ typedef enum {
     NSOtherErrorInvalidArgs
 } NSOtherErrorNumbers;
 
-extern void NSLinkEditError(
-    NSLinkEditErrors *c,
-    int *errorNumber, 
-    const char **fileName,
-    const char **errorString);
+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;
 
 typedef struct {
-     void     (*undefined)(const char *symbolName);
+     void     (*undefined)(const charsymbolName);
      NSModule (*multiple)(NSSymbol s, NSModule oldModule, NSModule newModule); 
      void     (*linkEdit)(NSLinkEditErrors errorClass, int errorNumber,
-                          const char *fileName, const char *errorString);
+                          const char* fileName, const char* errorString);
 } NSLinkEditErrorHandlers;
 
-extern void NSInstallLinkEditErrorHandlers(
-    const NSLinkEditErrorHandlers *handlers);
-
-/* other API */
-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);
+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 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;
 #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 int32_t NSVersionOfRunTimeLibrary(
-    const char *libraryName);
-extern int32_t NSVersionOfLinkTimeLibrary(
-    const char *libraryName);
-extern int _NSGetExecutablePath( /* SPI first appeared in Mac OS X 10.2 */
-    char *buf,
-    uint32_t *bufsize);
 
-/*
- * The low level _dyld_... API.
- * (used by the objective-C runtime primarily)
- */
-extern bool _dyld_present(
-    void);
-
-extern uint32_t _dyld_image_count(
-    void);
-extern const struct mach_header * _dyld_get_image_header(
-    uint32_t image_index);
-extern intptr_t _dyld_get_image_vmaddr_slide(
-    uint32_t image_index);
-extern const char * _dyld_get_image_name(
-    uint32_t image_index);
-
-extern void _dyld_register_func_for_add_image(
-    void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide));
-extern void _dyld_register_func_for_remove_image(
-    void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide));
-extern void _dyld_register_func_for_link_module(
-    void (*func)(NSModule module));
-/* not yet implemented */
-extern void _dyld_register_func_for_unlink_module(
-    void (*func)(NSModule module));
-/* not yet implemented */
-extern void _dyld_register_func_for_replace_module(
-    void (*func)(NSModule oldmodule, NSModule newmodule));
-extern void _dyld_get_objc_module_sect_for_module(
-    NSModule module,
-    void **objc_module,
-    size_t *size);
-extern void _dyld_bind_objc_module(
-    const void *objc_module);
-extern bool _dyld_bind_fully_image_containing_address(
-    const void *address);
-extern bool _dyld_image_containing_address(
-    const void* address);
-/* SPI first appeared in Mac OS X 10.3 */
-extern const struct mach_header * _dyld_get_image_header_containing_address(
-    const void* address)
-    AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
-
-extern void _dyld_moninit(
-    void (*monaddition)(char *lowpc, char *highpc));
-extern bool _dyld_launched_prebound(
-    void);
-/* SPI first appeared in Mac OS X 10.3 */
-extern bool _dyld_all_twolevel_modules_prebound(
-    void)
-    AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
-
-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_objc(
-    const char *symbol_name,
-    void **address,
-    NSModule* module);
-extern void _dyld_lookup_and_bind_fully(
-    const char *symbol_name,
-    void **address,
-    NSModule* module);
-
-extern int _dyld_func_lookup(
-    const char *dyld_func_name,
-    void **address);
+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;
+
 
 #if __cplusplus
 }
-#endif /* __cplusplus */
+#endif 
 
 #endif /* _MACH_O_DYLD_H_ */
index 9910dcd5dc3194f0f0ca1ce24566b1fb237a7151..04137accc65e3f5b351b1a78900a343bd49bbf7e 100644 (file)
  */
 #ifndef _DYLD_GDB_
 #define _DYLD_GDB_
+
 /*
- * This file describes the interface between gdb and dyld created for
- * MacOS X GM.  Prior to MacOS X GM gdb used the dyld_debug interfaces
- * described in <mach-o/dyld_debug.h>.
+ * For Mac OS X 10.4 or later, use the interface in mach-o/dylib_images.h
  */
-
+#include <mach-o/dyld_images.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-
-#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__
-
-#if OLD_GDB_DYLD_INTERFACE
+/*
+ * Prior to Mac OS 10.4, this is the interface gdb used to discover the mach-o images loaded in a process
+ */
+#if __ppc__ || __i386__
 /*
  * gdb_dyld_version is the version of gdb interface that dyld is currently
  * exporting.  For the interface described in this header file gdb_dyld_version
@@ -112,51 +111,7 @@ extern unsigned int gdb_nlibrary_images;
 /* the size of each gdb_library_image structure */
 extern unsigned int gdb_library_image_size;
 
-#endif /* OLD_GDB_DYLD_INTERFACE */
-
-
-/* 
- *     Beginning in Mac OS X 10.4, there is a new mechanism for dyld to notify gdb and other about new images.
- *
- *
- */
-
-enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
-
-struct dyld_image_info {
-       const struct mach_header*       imageLoadAddress;       /* base address image is mapped into */
-       const char*                                     imageFilePath;          /* path dyld used to load the image */
-       uintptr_t                                       imageFileModDate;       /* time_t of image file */
-                                                                                                       /* if stat().st_mtime of imageFilePath does not match imageFileModDate, */
-                                                                                                       /* then file has been modified since dyld loaded it */
-};
-
-
-typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
-
-/* 
- *     gdb looks for the symbol "_dyld_all_image_infos" in dyld.  It contains the fields below.  
- *
- *     For a snap shot of what images are currently loaded, the infoArray fields contain a pointer
- *     to an array of all images. If infoArray is NULL, it means it is being modified, come back later.
- *
- *     To be notified of changes, gdb sets a break point on the notification field.  The function
- *     it points to is called by dyld with an array of information about what images have been added
- *     (dyld_image_adding) or are about to be removed (dyld_image_removing). 
- *
- * 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.
- */
- struct dyld_all_image_infos {
-       uint32_t                                                version;                /* == 1 in Mac OS X 10.4 */
-       uint32_t                                                infoArrayCount;
-       const struct dyld_image_info*   infoArray;
-       dyld_image_notifier                             notification;           
-       bool                                                    processDetachedFromSharedRegion;
-};
-extern struct dyld_all_image_infos  dyld_all_image_infos;
-
+#endif 
 
 
 
diff --git a/include/mach-o/dyld_images.h b/include/mach-o/dyld_images.h
new file mode 100644 (file)
index 0000000..1f7b96b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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@
+ */
+#ifndef _DYLD_IMAGES_
+#define _DYLD_IMAGES_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* 
+ *     Beginning in Mac OS X 10.4, this is how gdb discovers which mach-o images are loaded in a process.
+ *
+ *     gdb looks for the symbol "_dyld_all_image_infos" in dyld.  It contains the fields below.  
+ *
+ *     For a snashot of what images are currently loaded, the infoArray fields contain a pointer
+ *     to an array of all images. If infoArray is NULL, it means it is being modified, come back later.
+ *
+ *     To be notified of changes, gdb sets a break point on the address pointed to by the notificationn
+ *     field.  The function it points to is called by dyld with an array of information about what images 
+ *     have been added (dyld_image_adding) or are about to be removed (dyld_image_removing). 
+ *
+ * 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.
+ */
+
+enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
+
+struct dyld_image_info {
+       const struct mach_header*       imageLoadAddress;       /* base address image is mapped into */
+       const char*                                     imageFilePath;          /* path dyld used to load the image */
+       uintptr_t                                       imageFileModDate;       /* time_t of image file */
+                                                                                                       /* if stat().st_mtime of imageFilePath does not match imageFileModDate, */
+                                                                                                       /* then file has been modified since dyld loaded it */
+};
+
+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                                                infoArrayCount;
+       const struct dyld_image_info*   infoArray;
+       dyld_image_notifier                             notification;           
+       bool                                                    processDetachedFromSharedRegion;
+};
+extern struct dyld_all_image_infos  dyld_all_image_infos;
+
+
+
+
+/*
+ * Beginning in Mac OS X 10.5, this is how gdb discovers where the shared cache is in a process.
+ * Images that are in the shared cache have their segments rearranged, so when using imageFilePath
+ * to load the file from disk, you have to know to adjust addresses based on how their segment
+ * was rearranged.
+ *
+ * gdb looks for the symbol "_dyld_shared_region_ranges" in dyld. 
+ * 
+ * It contains information the count of shared regions used by the process.  The count is
+ * the number of start/length pairs.  
+ */
+struct dyld_shared_cache_ranges {
+       uintptr_t                                       sharedRegionsCount;     /* how many ranges follow */
+       struct {
+               uintptr_t       start;
+               uintptr_t       length;
+       }                                                       ranges[4];                      /* max regions */
+};
+extern struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DYLD_IMAGES_ */
index 5111ebb3ccc2aef1ef082a5cfbf78b973f416e2b..8d327f4cb6b049fcabf01da4c3df2aa09cb7a604 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,6 +26,7 @@
 
 
 #include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
 
 #if __cplusplus
 extern "C" {
@@ -51,6 +53,53 @@ NSFindSectionAndOffsetInObjectFileImage(
     unsigned long* sectionOffset);     /* can be NULL */
 
 
+//
+// Possible state changes for which you can register to be notified
+//
+enum dyld_image_states
+{
+       dyld_image_state_mapped                                 = 10,           // No batch notification for this
+       dyld_image_state_dependents_mapped              = 20,           // Only batch notification for this
+       dyld_image_state_rebased                                = 30, 
+       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
+};
+
+// 
+// Callback that provides a bottom-up array of images
+// For dyld_image_state_[dependents_]mapped state only, returning non-NULL will cause dyld to abort loading all those images
+// and append the returned string to its load failure error message. dyld does not free the string, so
+// it should be a literal string or a static buffer
+//
+typedef const char* (*dyld_image_state_change_handler)(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[]);
+
+//
+// Register a handler to be called when any image changes to the requested state.
+// If 'batch' is true, the callback is called with an array of all images that are in the requested state sorted by dependency.
+// If 'batch' is false, the callback is called with one image at a time as each image transitions to the the requested state.
+// During the call to this function, the handler may be called back with existing images and the handler should
+// not return a string, since there is no load to abort.  In batch mode, existing images at or past the request
+// state supplied in the callback.  In non-batch mode, the callback is called for each image exactly in the
+// requested state.    
+//
+extern void
+dyld_register_image_state_change_handler(enum dyld_image_states state, bool batch, dyld_image_state_change_handler handler);
+
+
+//
+//
+//
+extern void
+_dyld_library_locator(const char* (*handler)(const char*));
+
+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) */
+
+
 
 
 #if __cplusplus
diff --git a/launch-cache/Architectures.hpp b/launch-cache/Architectures.hpp
new file mode 100644 (file)
index 0000000..e735f9e
--- /dev/null
@@ -0,0 +1,80 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+#ifndef __ARCHITECTURES__
+#define __ARCHITECTURES__
+
+#include "FileAbstraction.hpp"
+
+
+//
+// Architectures
+//
+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 };
+};
+
+
+
+
+
+
+#endif // __ARCHITECTURES__
+
+
diff --git a/launch-cache/CacheFileAbstraction.hpp b/launch-cache/CacheFileAbstraction.hpp
new file mode 100644 (file)
index 0000000..cb98ac3
--- /dev/null
@@ -0,0 +1,116 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+#ifndef __DYLD_CACHE_ABSTRACTION__
+#define __DYLD_CACHE_ABSTRACTION__
+
+#include "dyld_cache_format.h"
+
+#include "FileAbstraction.hpp"
+#include "Architectures.hpp"
+
+template <typename E>
+class dyldCacheHeader {
+public:
+       const char*             magic() const                                                   INLINE { return fields.magic; }
+       void                    set_magic(const char* value)                    INLINE { memcpy(fields.magic, value, 16); }
+
+       //uint32_t              architecture() const                                    INLINE { return E::get32(fields.architecture); }
+       //void                  set_architecture(uint32_t value)                INLINE { E::set32(fields.architecture, value); }
+
+       uint32_t                mappingOffset() const                                   INLINE { return E::get32(fields.mappingOffset); }
+       void                    set_mappingOffset(uint32_t value)               INLINE { E::set32(fields.mappingOffset, value); }
+
+       uint32_t                mappingCount() const                                    INLINE { return E::get32(fields.mappingCount); }
+       void                    set_mappingCount(uint32_t value)                INLINE { E::set32(fields.mappingCount, value); }
+
+       uint32_t                imagesOffset() const                                    INLINE { return E::get32(fields.imagesOffset); }
+       void                    set_imagesOffset(uint32_t value)                INLINE { E::set32(fields.imagesOffset, value); }
+
+       uint32_t                imagesCount() const                                             INLINE { return E::get32(fields.imagesCount); }
+       void                    set_imagesCount(uint32_t value)                 INLINE { E::set32(fields.imagesCount, value); }
+
+       uint64_t                dyldBaseAddress() const                                 INLINE { return E::get64(fields.dyldBaseAddress); }
+       void                    set_dyldBaseAddress(uint64_t value)             INLINE { E::set64(fields.dyldBaseAddress, value); }
+
+       //uint32_t              dependenciesOffset() const                              INLINE { return E::get32(fields.dependenciesOffset); }
+       //void                  set_dependenciesOffset(uint32_t value)  INLINE { E::set32(fields.dependenciesOffset, value); }
+
+       //uint32_t              dependenciesCount() const                               INLINE { return E::get32(fields.dependenciesCount); }
+       //void                  set_dependenciesCount(uint32_t value)   INLINE { E::set32(fields.dependenciesCount, value); }
+
+private:
+       dyld_cache_header                       fields;
+};
+
+
+template <typename E>
+class dyldCacheFileMapping {
+public:                
+       uint64_t                address() const                                                         INLINE { return E::get64(fields.sfm_address); }
+       void                    set_address(uint64_t value)                                     INLINE { E::set64(fields.sfm_address, value); }
+
+       uint64_t                size() const                                                            INLINE { return E::get64(fields.sfm_size); }
+       void                    set_size(uint64_t value)                                        INLINE { E::set64(fields.sfm_size, value); }
+
+       uint64_t                file_offset() const                                                     INLINE { return E::get64(fields.sfm_file_offset); }
+       void                    set_file_offset(uint64_t value)                         INLINE { E::set64(fields.sfm_file_offset, value); }
+
+       uint32_t                max_prot() const                                                        INLINE { return E::get32(fields.sfm_max_prot); }
+       void                    set_max_prot(uint32_t value)                            INLINE { E::set32((uint32_t&)fields.sfm_max_prot, value); }
+
+       uint32_t                init_prot() const                                                       INLINE { return E::get32(fields.sfm_init_prot); }
+       void                    set_init_prot(uint32_t value)                           INLINE { E::set32((uint32_t&)fields.sfm_init_prot, value); }
+
+private:
+       shared_file_mapping_np                  fields;
+};
+
+
+template <typename E>
+class dyldCacheImageInfo {
+public:                
+       uint64_t                address() const                                                         INLINE { return E::get64(fields.address); }
+       void                    set_address(uint64_t value)                                     INLINE { E::set64(fields.address, value); }
+
+       uint64_t                modTime() const                                                         INLINE { return E::get64(fields.modTime); }
+       void                    set_modTime(uint64_t value)                                     INLINE { E::set64(fields.modTime, value); }
+
+       uint64_t                inode() const                                                           INLINE { return E::get64(fields.inode); }
+       void                    set_inode(uint64_t value)                                       INLINE { E::set64(fields.inode, value); }
+
+       uint32_t                pathFileOffset() const                                          INLINE { return E::get32(fields.pathFileOffset); }
+       void                    set_pathFileOffset(uint32_t value)                      INLINE { E::set32(fields.pathFileOffset, value); fields.pad=0; }
+
+       //uint32_t              dependenciesStartOffset() const                         INLINE { return E::get32(fields.dependenciesStartOffset); }
+       //void                  set_dependenciesStartOffset(uint32_t value)     INLINE { E::set32(fields.dependenciesStartOffset, value); }
+
+private:
+       dyld_cache_image_info                   fields;
+};
+
+
+
+#endif // __DYLD_CACHE_ABSTRACTION__
+
+
diff --git a/launch-cache/FileAbstraction.hpp b/launch-cache/FileAbstraction.hpp
new file mode 100644 (file)
index 0000000..1f7a629
--- /dev/null
@@ -0,0 +1,145 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+#ifndef __FILE_ABSTRACTION__
+#define __FILE_ABSTRACTION__
+
+
+#include <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#ifdef __OPTIMIZE__
+#define INLINE __attribute__((always_inline))
+#else
+#define INLINE
+#endif
+
+//
+// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
+//
+// For example: to make a utility that handles 32-bit little enidan files use:  Pointer32<LittleEndian>
+//
+//
+//             get16()                 read a 16-bit number from an E endian struct
+//             set16()                 write a 16-bit number to an E endian struct
+//             get32()                 read a 32-bit number from an E endian struct
+//             set32()                 write a 32-bit number to an E endian struct
+//             get64()                 read a 64-bit number from an E endian struct
+//             set64()                 write a 64-bit number to an E endian struct
+//
+//             getBits()               read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//             setBits()               write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//
+//             getBitsRaw()    read a bit field from a struct with native endianness
+//             setBitsRaw()    write a bit field from a struct with native endianness
+//
+
+class BigEndian
+{
+public:
+       static uint16_t get16(const uint16_t& from)                             INLINE { return OSReadBigInt16(&from, 0); }
+       static void             set16(uint16_t& into, uint16_t value)   INLINE { OSWriteBigInt16(&into, 0, value); }
+       
+       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 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); }
+       
+       static uint32_t getBits(const uint32_t& from, 
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+       static void             setBits(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+       static uint32_t getBitsRaw(const uint32_t& from, 
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
+       static void             setBitsRaw(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = into; 
+                                                                                                                                                                                       const uint32_t mask = ((1<<bitCount)-1); 
+                                                                                                                                                                                       temp &= ~(mask << (32-firstBit-bitCount)); 
+                                                                                                                                                                                       temp |= ((value & mask) << (32-firstBit-bitCount)); 
+                                                                                                                                                                                       into = temp; }
+       enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+       static uint16_t get16(const uint16_t& from)                             INLINE { return OSReadLittleInt16(&from, 0); }
+       static void             set16(uint16_t& into, uint16_t value)   INLINE { OSWriteLittleInt16(&into, 0, value); }
+       
+       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 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); }
+
+       static uint32_t getBits(const uint32_t& from,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+       static void             setBits(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+       static uint32_t getBitsRaw(const uint32_t& from,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
+       static void             setBitsRaw(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE {  uint32_t temp = into; 
+                                                                                                                                                                                       const uint32_t mask = ((1<<bitCount)-1); 
+                                                                                                                                                                                       temp &= ~(mask << firstBit); 
+                                                                                                                                                                                       temp |= ((value & mask) << firstBit); 
+                                                                                                                                                                                       into = temp; }
+       enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+class Pointer32
+{
+public:
+       typedef uint32_t        uint_t;
+       typedef _E                      E;
+       
+       static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
+       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, value); }
+};
+
+
+template <typename _E>
+class Pointer64
+{
+public:
+       typedef uint64_t        uint_t;
+       typedef _E                      E;
+       
+       static uint64_t getP(const uint_t& from)                                INLINE { return _E::get64(from); }
+       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set64(into, value); }
+};
+
+
+
+
+
+#endif // __FILE_ABSTRACTION__
+
+
diff --git a/launch-cache/MachOBinder.hpp b/launch-cache/MachOBinder.hpp
new file mode 100644 (file)
index 0000000..cb37248
--- /dev/null
@@ -0,0 +1,590 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+
+#ifndef __MACHO_BINDER__
+#define __MACHO_BINDER__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+#include <vector>
+#include <set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "MachOLayout.hpp"
+#include "MachORebaser.hpp"
+
+
+
+
+template <typename A>
+class Binder : public Rebaser<A>
+{
+public:
+       struct CStringEquals {
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, class Binder<A>*, __gnu_cxx::hash<const char*>, CStringEquals> Map;
+
+
+                                                                                               Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress);
+       virtual                                                                         ~Binder() {}
+       
+       const char*                                                                     getDylibID() const;
+       void                                                                            setDependentBinders(const Map& map);
+       void                                                                            bind();
+
+private:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+       struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
+       typedef __gnu_cxx::hash_map<const char*, const macho_nlist<P>*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSymbolMap;
+       
+       void                                                                            doBindExternalRelocations();
+       void                                                                            doBindIndirectSymbols();
+       void                                                                            doSetUpDyldSection();
+       void                                                                            doSetPreboundUndefines();
+       pint_t                                                                          resolveUndefined(const macho_nlist<P>* undefinedSymbol);
+       const macho_nlist<P>*                                           findExportedSymbol(const char* name);
+       void                                                                            bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
+       const char*                                                                     parentUmbrella();
+
+       static uint8_t                                                          pointerRelocSize();
+       static uint8_t                                                          pointerRelocType();
+       
+       std::vector<BinderAndReExportFlag>                      fDependentDylibs;
+       NameToSymbolMap                                                         fHashTable;
+       uint64_t                                                                        fDyldBaseAddress;
+       const macho_nlist<P>*                                           fSymbolTable;
+       const char*                                                                     fStrings;
+       const macho_dysymtab_command<P>*                        fDynamicInfo;
+       const macho_segment_command<P>*                         fFristWritableSegment;
+       const macho_dylib_command<P>*                           fDylibID;
+       const macho_dylib_command<P>*                           fParentUmbrella;
+       bool                                                                            fOriginallyPrebound;
+};
+
+
+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),
+         fParentUmbrella(NULL)
+{
+       fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
+       // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
+       ((macho_header<P>*)this->fHeader)->set_flags(this->fHeader->flags() | MH_PREBOUND | MH_SPLIT_SEGS | 0x80000000);
+
+       // calculate fDynamicInfo, fStrings, fSymbolTable
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = this->fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+                               fSymbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
+                               fStrings = (const char*)&this->fLinkEditBase[symtab->stroff()];
+                               break;
+                       case LC_DYSYMTAB:
+                               fDynamicInfo = (macho_dysymtab_command<P>*)cmd;
+                               break;
+                       case LC_ID_DYLIB:
+                               ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
+                               fDylibID = (macho_dylib_command<P>*)cmd;
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                               ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
+                               break;
+                       case LC_SUB_FRAMEWORK:
+                               fParentUmbrella = (macho_dylib_command<P>*)cmd;
+                               break;
+                       default:
+                               if ( cmd->cmd() & LC_REQ_DYLD )
+                                       throwf("unknown required load command %d", cmd->cmd());
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+       if ( fDynamicInfo == NULL )     
+               throw "no LC_DYSYMTAB";
+       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;
+               }
+       }
+       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;
+               }
+       }
+
+}
+
+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<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 <typename A>
+const char* Binder<A>::getDylibID() const
+{
+       if ( fDylibID != NULL )
+               return fDylibID->name();
+       else
+               return NULL;
+}
+
+template <typename A>
+const char* Binder<A>::parentUmbrella()
+{
+       if ( fParentUmbrella != NULL )
+               return fParentUmbrella->name();
+       else
+               return NULL;
+}
+
+
+
+template <typename A>
+void Binder<A>::setDependentBinders(const Map& map)
+{
+       // first pass to build vector of dylibs
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = this->fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                               const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
+                               typename Map::const_iterator pos = map.find(path);
+                               if ( pos != map.end() ) {
+                                       BinderAndReExportFlag entry;
+                                       entry.binder = pos->second;
+                                       entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
+                                       fDependentDylibs.push_back(entry);
+                               }
+                               else {
+                                       // the load command string does not match the install name of any loaded dylib
+                                       // this could happen if there was not a world build and some dylib changed its
+                                       // install path to be some symlinked path
+                                       
+                                       // use realpath() and walk map looking for a realpath match
+                                       bool found = false;
+                                       char targetPath[PATH_MAX];
+                                       if ( realpath(path, targetPath) != NULL ) {
+                                               for(typename Map::const_iterator it=map.begin(); it != map.end(); ++it) {
+                                                       char aPath[PATH_MAX];
+                                                       if ( realpath(it->first, aPath) != NULL ) {
+                                                               if ( strcmp(targetPath, aPath) == 0 ) {
+                                                                       BinderAndReExportFlag entry;
+                                                                       entry.binder = it->second;
+                                                                       entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
+                                                                       fDependentDylibs.push_back(entry);
+                                                                       found = true;
+                                                                       fprintf(stderr, "update_dyld_shared_cache: warning mismatched install path in %s for %s\n", 
+                                                                               this->getDylibID(), path);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if ( ! found )
+                                               throwf("in %s can't find dylib %s", this->getDylibID(), path);
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       // handle pre-10.5 re-exports 
+       if ( (this->fHeader->flags() & MH_NO_REEXPORTED_DYLIBS) == 0 ) {
+               cmd = cmds;
+               // LC_SUB_LIBRARY means re-export one with matching leaf name
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       switch ( cmd->cmd() ) {
+                               case LC_SUB_LIBRARY:
+                                       const char* dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
+                                       for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
+                                               const char* dylibName = it->binder->getDylibID();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               const char* leafStart = &lastSlash[1];
+                                               if ( lastSlash == NULL )
+                                                       leafStart = dylibName;
+                                               const char* firstDot = strchr(leafStart, '.');
+                                               int len = strlen(leafStart);
+                                               if ( firstDot != NULL )
+                                                       len = firstDot - leafStart;
+                                               if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+                                                       it->reExport = true;
+                                       }
+                                       break;
+                               case LC_SUB_UMBRELLA:
+                                       const char* frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
+                                       for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
+                                               const char* dylibName = it->binder->getDylibID();
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+                                                       it->reExport = true;
+                                       }
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+               }
+               // ask dependents if they re-export through me
+               const char* thisName = this->getDylibID();
+               if ( thisName != NULL ) {
+                       const char* thisLeafName = strrchr(thisName, '/');
+                       if ( thisLeafName != NULL )
+                               ++thisLeafName;
+                       for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
+                               if ( ! it->reExport ) {
+                                       const char* parentUmbrellaName = it->binder->parentUmbrella();
+                                       if ( parentUmbrellaName != NULL ) {
+                                               if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
+                                                       it->reExport = true;
+                                       }
+                               }
+                       }       
+               }
+       }
+}
+
+template <typename A>
+void Binder<A>::bind()
+{
+       this->doSetUpDyldSection();
+       this->doBindExternalRelocations();
+       this->doBindIndirectSymbols();
+       this->doSetPreboundUndefines();
+}
+
+
+template <typename A>
+void Binder<A>::doSetUpDyldSection()
+{
+       // find __DATA __dyld section 
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = this->fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                       if ( strcmp(seg->segname(), "__DATA") == 0 ) {
+                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
+                               const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                               for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                       if ( (strcmp(sect->sectname(), "__dyld") == 0) && (sect->size() >= 2*sizeof(pint_t)) ) {
+                                               // set two values in __dyld section to point into dyld
+                                               pint_t* lazyBinder = this->mappedAddressForNewAddress(sect->addr());
+                                               pint_t* dyldFuncLookup = this->mappedAddressForNewAddress(sect->addr()+sizeof(pint_t));
+                                               A::P::setP(*lazyBinder, fDyldBaseAddress + 0x1000);
+                                               A::P::setP(*dyldFuncLookup, fDyldBaseAddress + 0x1008);
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+template <typename A>
+void Binder<A>::doSetPreboundUndefines()
+{
+       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*)this->fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = this->fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               {
+                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+                                       symbolTable = (macho_nlist<P>*)(&this->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());
+       }       
+       
+       // walk all undefines and set their prebound n_value
+       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());
+                       entry->set_n_value(pbaddr);
+               }
+       }
+}
+
+
+template <typename A>
+void Binder<A>::doBindExternalRelocations()
+{
+       // get where reloc addresses start
+       // these address are always relative to first writable segment because they are in cache which always
+       // has writable segments far from read-only segments
+       pint_t firstWritableSegmentBaseAddress = 0;
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( seg.writable() ) {
+                       firstWritableSegmentBaseAddress = seg.newAddress();
+                       break;
+               }
+       }       
+       
+       // loop through all external relocation records and bind each
+       const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&this->fLinkEditBase[fDynamicInfo->extreloff()]);
+       const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicInfo->nextrel()];
+       for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               if ( reloc->r_length() != pointerRelocSize() ) 
+                       throw "bad external relocation length";
+               if ( reloc->r_type() != pointerRelocType() ) 
+                       throw "unknown external relocation type";
+               if ( reloc->r_pcrel() ) 
+                       throw "r_pcrel external relocaiton not supported";
+
+               const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
+               pint_t* location;
+               try {
+                       location = mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
+               }
+               catch (const char* msg) {
+                       throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
+               }
+               pint_t addend =  P::getP(*location);
+               if ( fOriginallyPrebound ) {
+                       // in a prebound binary, 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.
+                       addend -= undefinedSymbol->n_value();
+                       // To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
+                       // new base address, so we need to back off the slide too..
+                       if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
+                               addend += this->getSlideForNewAddress(undefinedSymbol->n_value());
+                       }
+               }
+               pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
+               //fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n", 
+               //              reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
+               P::setP(*location, symbolAddr + addend); 
+       }
+}
+
+
+// most architectures use pure code, unmodifiable stubs
+template <typename A>
+void Binder<A>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
+{
+       // do nothing
+}
+
+// x86 supports fast stubs
+template <>
+void Binder<x86>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
+{
+       // if the stub is not 5-bytes, it is an old slow stub
+       if ( elementSize == 5 ) {
+               uint32_t rel32 = value - (vmlocation + 5);
+               location[0] = 0xE9; // JMP rel32
+               location[1] = rel32 & 0xFF;
+               location[2] = (rel32 >> 8) & 0xFF;
+               location[3] = (rel32 >> 16) & 0xFF;
+               location[4] = (rel32 >> 24) & 0xFF;
+       }
+}
+
+template <typename A>
+void Binder<A>::doBindIndirectSymbols()
+{
+       const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = this->fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
+                       const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                               uint8_t elementSize = 0;
+                               uint8_t sectionType = sect->flags() & SECTION_TYPE;
+                               switch ( sectionType ) {
+                                       case S_SYMBOL_STUBS:
+                                               elementSize = sect->reserved2();
+                                               break;
+                                       case S_NON_LAZY_SYMBOL_POINTERS:
+                                       case S_LAZY_SYMBOL_POINTERS:
+                                               elementSize = sizeof(pint_t);
+                                               break;
+                               }
+                               if ( elementSize != 0 ) {
+                                       uint32_t elementCount = sect->size() / elementSize;
+                                       const uint32_t indirectTableOffset = sect->reserved1();
+                                       uint8_t* location = NULL; 
+                                       if ( sect->size() != 0 )
+                                               location = (uint8_t*)this->mappedAddressForNewAddress(sect->addr());
+                                       pint_t vmlocation = sect->addr();
+                                       for (uint32_t j=0; j < elementCount; ++j, location += elementSize, vmlocation += elementSize) {
+                                               uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]); 
+                                               switch ( symbolIndex ) {
+                                                       case INDIRECT_SYMBOL_ABS:
+                                                       case INDIRECT_SYMBOL_LOCAL:
+                                                               break;
+                                                       default:
+                                                               const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
+                                                               pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
+                                                               switch ( sectionType ) {
+                                                                       case S_NON_LAZY_SYMBOL_POINTERS:
+                                                                       case S_LAZY_SYMBOL_POINTERS:
+                                                                               P::setP(*((pint_t*)location), symbolAddr); 
+                                                                               break;
+                                                                       case S_SYMBOL_STUBS:
+                                                                               this->bindStub(elementSize, location, vmlocation, symbolAddr);
+                                                                                       break;
+                                                               }
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+
+
+template <typename A>
+typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefinedSymbol)
+{
+       if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
+               if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
+                       // is a multi-module private_extern internal reference that the linker did not optimize away
+                       return undefinedSymbol->n_value();
+               }
+               if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
+                       // is a weak definition, we should prebind to this one in the same linkage unit
+                       return undefinedSymbol->n_value();
+               }
+       }
+       const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
+       if ( (this->fHeader->flags() & MH_TWOLEVEL) == 0 ) {
+               // flat namespace binding
+               throw "flat namespace not supported";
+       }
+       else {
+               uint8_t ordinal = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc());
+               Binder<A>* binder = NULL;
+               switch ( ordinal ) {
+                       case EXECUTABLE_ORDINAL:
+                       case DYNAMIC_LOOKUP_ORDINAL:
+                               throw "magic ordineal not supported";
+                       case SELF_LIBRARY_ORDINAL:
+                               binder = this;
+                               break;
+                       default:
+                               if ( ordinal > fDependentDylibs.size() )
+                                       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();
+       }
+}
+
+template <typename A>
+const macho_nlist<typename A::P>* Binder<A>::findExportedSymbol(const char* name)
+{
+       //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;
+
+       // 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;
+               }
+       }
+       return NULL;
+}
+
+
+
+#endif // __MACHO_BINDER__
+
+
+
+
diff --git a/launch-cache/MachOFileAbstraction.hpp b/launch-cache/MachOFileAbstraction.hpp
new file mode 100644 (file)
index 0000000..dadec7b
--- /dev/null
@@ -0,0 +1,738 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+*/
+#ifndef __MACH_O_FILE_ABSTRACTION__
+#define __MACH_O_FILE_ABSTRACTION__
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach/machine.h>
+
+// suport older versions of mach-o/loader.h
+#ifndef LC_UUID
+#define LC_UUID                0x1b
+struct uuid_command {
+    uint32_t   cmd;            /* LC_UUID */
+    uint32_t   cmdsize;        /* sizeof(struct uuid_command) */
+    uint8_t    uuid[16];       /* the 128-bit uuid */
+};
+#endif
+
+#ifndef S_16BYTE_LITERALS
+       #define S_16BYTE_LITERALS 0xE
+#endif
+
+#include "FileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+
+//
+// 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
+//
+template <typename P>
+class macho_load_command {
+public:
+       uint32_t                cmd() const                                             INLINE { return E::get32(command.cmd); }
+       void                    set_cmd(uint32_t value)                 INLINE { E::set32(command.cmd, value); }
+
+       uint32_t                cmdsize() const                                 INLINE { return E::get32(command.cmdsize); }
+       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(command.cmdsize, value); }
+
+       typedef typename P::E           E;
+private:
+       load_command    command;
+};
+
+
+//
+// mach-o segment load command
+//
+template <typename P> struct macho_segment_content {};
+template <> struct macho_segment_content<Pointer32<BigEndian> >    { segment_command   fields; enum { CMD = LC_SEGMENT         }; };
+template <> struct macho_segment_content<Pointer64<BigEndian> >           { segment_command_64 fields; enum { CMD = LC_SEGMENT_64      }; };
+template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command   fields; enum { CMD = LC_SEGMENT         }; };
+template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64        fields; enum { CMD = LC_SEGMENT_64      }; };
+
+template <typename P>
+class macho_segment_command {
+public:
+       uint32_t                cmd() const                                             INLINE { return E::get32(segment.fields.cmd); }
+       void                    set_cmd(uint32_t value)                 INLINE { E::set32(segment.fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                 INLINE { return E::get32(segment.fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(segment.fields.cmdsize, value); }
+
+       const char*             segname() const                                 INLINE { return segment.fields.segname; }
+       void                    set_segname(const char* value)  INLINE { strncpy(segment.fields.segname, value, 16); }
+       
+       uint64_t                vmaddr() const                                  INLINE { return P::getP(segment.fields.vmaddr); }
+       void                    set_vmaddr(uint64_t value)              INLINE { P::setP(segment.fields.vmaddr, value); }
+
+       uint64_t                vmsize() const                                  INLINE { return P::getP(segment.fields.vmsize); }
+       void                    set_vmsize(uint64_t value)              INLINE { P::setP(segment.fields.vmsize, value); }
+
+       uint64_t                fileoff() const                                 INLINE { return P::getP(segment.fields.fileoff); }
+       void                    set_fileoff(uint64_t value)             INLINE { P::setP(segment.fields.fileoff, value); }
+
+       uint64_t                filesize() const                                INLINE { return P::getP(segment.fields.filesize); }
+       void                    set_filesize(uint64_t value)    INLINE { P::setP(segment.fields.filesize, value); }
+
+       uint32_t                maxprot() const                                 INLINE { return E::get32(segment.fields.maxprot); }
+       void                    set_maxprot(uint32_t value)             INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
+
+       uint32_t                initprot() const                                INLINE { return E::get32(segment.fields.initprot); }
+       void                    set_initprot(uint32_t value)    INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
+
+       uint32_t                nsects() const                                  INLINE { return E::get32(segment.fields.nsects); }
+       void                    set_nsects(uint32_t value)              INLINE { E::set32(segment.fields.nsects, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(segment.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(segment.fields.flags, value); }
+
+       enum {
+               CMD = macho_segment_content<P>::CMD
+       };
+
+       typedef typename P::E           E;
+private:
+       macho_segment_content<P>        segment;
+};
+
+
+//
+// mach-o section 
+//
+template <typename P> struct macho_section_content {};
+template <> struct macho_section_content<Pointer32<BigEndian> >    { section   fields; };
+template <> struct macho_section_content<Pointer64<BigEndian> >           { section_64 fields; };
+template <> struct macho_section_content<Pointer32<LittleEndian> > { section   fields; };
+template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64        fields; };
+
+template <typename P>
+class macho_section {
+public:
+       const char*             sectname() const                                INLINE { return section.fields.sectname; }
+       void                    set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); }
+       
+       const char*             segname() const                                 INLINE { return section.fields.segname; }
+       void                    set_segname(const char* value)  INLINE { strncpy(section.fields.segname, value, 16); }
+       
+       uint64_t                addr() const                                    INLINE { return P::getP(section.fields.addr); }
+       void                    set_addr(uint64_t value)                INLINE { P::setP(section.fields.addr, value); }
+
+       uint64_t                size() const                                    INLINE { return P::getP(section.fields.size); }
+       void                    set_size(uint64_t value)                INLINE { P::setP(section.fields.size, value); }
+
+       uint32_t                offset() const                                  INLINE { return E::get32(section.fields.offset); }
+       void                    set_offset(uint32_t value)              INLINE { E::set32(section.fields.offset, value); }
+
+       uint32_t                align() const                                   INLINE { return E::get32(section.fields.align); }
+       void                    set_align(uint32_t value)               INLINE { E::set32(section.fields.align, value); }
+
+       uint32_t                reloff() const                                  INLINE { return E::get32(section.fields.reloff); }
+       void                    set_reloff(uint32_t value)              INLINE { E::set32(section.fields.reloff, value); }
+
+       uint32_t                nreloc() const                                  INLINE { return E::get32(section.fields.nreloc); }
+       void                    set_nreloc(uint32_t value)              INLINE { E::set32(section.fields.nreloc, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(section.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(section.fields.flags, value); }
+
+       uint32_t                reserved1() const                               INLINE { return E::get32(section.fields.reserved1); }
+       void                    set_reserved1(uint32_t value)   INLINE { E::set32(section.fields.reserved1, value); }
+
+       uint32_t                reserved2() const                               INLINE { return E::get32(section.fields.reserved2); }
+       void                    set_reserved2(uint32_t value)   INLINE { E::set32(section.fields.reserved2, value); }
+
+       typedef typename P::E           E;
+private:
+       macho_section_content<P>        section;
+};
+
+
+//
+// mach-o dylib load command
+//
+template <typename P>
+class macho_dylib_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                name_offset() const                                                     INLINE { return E::get32(fields.dylib.name.offset); }
+       void                    set_name_offset(uint32_t value)                         INLINE { E::set32(fields.dylib.name.offset, value);  }
+       
+       uint32_t                timestamp() const                                                       INLINE { return E::get32(fields.dylib.timestamp); }
+       void                    set_timestamp(uint32_t value)                           INLINE { E::set32(fields.dylib.timestamp, value); }
+
+       uint32_t                current_version() const                                         INLINE { return E::get32(fields.dylib.current_version); }
+       void                    set_current_version(uint32_t value)                     INLINE { E::set32(fields.dylib.current_version, value); }
+
+       uint32_t                compatibility_version() const                           INLINE { return E::get32(fields.dylib.compatibility_version); }
+       void                    set_compatibility_version(uint32_t value)       INLINE { E::set32(fields.dylib.compatibility_version, value); }
+
+       const char*             name() const                                                            INLINE { return (const char*)&fields + name_offset(); }
+       void                    set_name_offset()                                                       INLINE { set_name_offset(sizeof(fields)); }
+       
+       typedef typename P::E           E;
+private:
+       dylib_command   fields;
+};
+
+
+//
+// mach-o dylinker load command
+//
+template <typename P>
+class macho_dylinker_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                name_offset() const                                     INLINE { return E::get32(fields.name.offset); }
+       void                    set_name_offset(uint32_t value)         INLINE { E::set32(fields.name.offset, value);  }
+       
+       const char*             name() const                                            INLINE { return (const char*)&fields + name_offset(); }
+       void                    set_name_offset()                                       INLINE { set_name_offset(sizeof(fields)); }
+       
+       typedef typename P::E           E;
+private:
+       dylinker_command        fields;
+};
+
+
+//
+// mach-o sub_framework load command
+//
+template <typename P>
+class macho_sub_framework_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                umbrella_offset() const                         INLINE { return E::get32(fields.umbrella.offset); }
+       void                    set_umbrella_offset(uint32_t value)     INLINE { E::set32(fields.umbrella.offset, value);  }
+       
+       const char*             umbrella() const                                        INLINE { return (const char*)&fields + umbrella_offset(); }
+       void                    set_umbrella_offset()                           INLINE { set_umbrella_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_framework_command   fields;
+};
+
+
+//
+// mach-o sub_client load command
+//
+template <typename P>
+class macho_sub_client_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                client_offset() const                           INLINE { return E::get32(fields.client.offset); }
+       void                    set_client_offset(uint32_t value)       INLINE { E::set32(fields.client.offset, value);  }
+       
+       const char*             client() const                                          INLINE { return (const char*)&fields + client_offset(); }
+       void                    set_client_offset()                                     INLINE { set_client_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_client_command      fields;
+};
+
+
+//
+// mach-o sub_umbrella load command
+//
+template <typename P>
+class macho_sub_umbrella_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                sub_umbrella_offset() const                             INLINE { return E::get32(fields.sub_umbrella.offset); }
+       void                    set_sub_umbrella_offset(uint32_t value) INLINE { E::set32(fields.sub_umbrella.offset, value);  }
+       
+       const char*             sub_umbrella() const                                    INLINE { return (const char*)&fields + sub_umbrella_offset(); }
+       void                    set_sub_umbrella_offset()                               INLINE { set_sub_umbrella_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_umbrella_command    fields;
+};
+
+
+//
+// mach-o sub_library load command
+//
+template <typename P>
+class macho_sub_library_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                sub_library_offset() const                              INLINE { return E::get32(fields.sub_library.offset); }
+       void                    set_sub_library_offset(uint32_t value)  INLINE { E::set32(fields.sub_library.offset, value);  }
+       
+       const char*             sub_library() const                                             INLINE { return (const char*)&fields + sub_library_offset(); }
+       void                    set_sub_library_offset()                                INLINE { set_sub_library_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_library_command     fields;
+};
+
+
+//
+// mach-o uuid load command
+//
+template <typename P>
+class macho_uuid_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); }
+
+       const uint8_t*  uuid() const                                                    INLINE { return fields.uuid; }
+       void                    set_uuid(uint8_t value[16])                             INLINE { memcpy(&fields.uuid, value, 16); }
+                       
+       typedef typename P::E           E;
+private:
+       uuid_command    fields;
+};
+
+
+//
+// mach-o routines load command
+//
+template <typename P> struct macho_routines_content {};
+template <> struct macho_routines_content<Pointer32<BigEndian> >    { routines_command         fields; enum { CMD = LC_ROUTINES        }; };
+template <> struct macho_routines_content<Pointer64<BigEndian> >       { routines_command_64   fields; enum { CMD = LC_ROUTINES_64     }; };
+template <> struct macho_routines_content<Pointer32<LittleEndian> > { routines_command         fields; enum { CMD = LC_ROUTINES        }; };
+template <> struct macho_routines_content<Pointer64<LittleEndian> > { routines_command_64      fields; enum { CMD = LC_ROUTINES_64     }; };
+
+template <typename P>
+class macho_routines_command {
+public:
+       uint32_t                cmd() const                                                     INLINE { return E::get32(routines.fields.cmd); }
+       void                    set_cmd(uint32_t value)                         INLINE { E::set32(routines.fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                         INLINE { return E::get32(routines.fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                     INLINE { E::set32(routines.fields.cmdsize, value); }
+
+       uint64_t                init_address() const                            INLINE { return P::getP(routines.fields.init_address); }
+       void                    set_init_address(uint64_t value)        INLINE { P::setP(routines.fields.init_address, value); }
+
+       uint64_t                init_module() const                                     INLINE { return P::getP(routines.fields.init_module); }
+       void                    set_init_module(uint64_t value)         INLINE { P::setP(routines.fields.init_module, value); }
+
+       uint64_t                reserved1() const                                       INLINE { return P::getP(routines.fields.reserved1); }
+       void                    set_reserved1(uint64_t value)           INLINE { P::setP(routines.fields.reserved1, value); }
+       
+       uint64_t                reserved2() const                                       INLINE { return P::getP(routines.fields.reserved2); }
+       void                    set_reserved2(uint64_t value)           INLINE { P::setP(routines.fields.reserved2, value); }
+       
+       uint64_t                reserved3() const                                       INLINE { return P::getP(routines.fields.reserved3); }
+       void                    set_reserved3(uint64_t value)           INLINE { P::setP(routines.fields.reserved3, value); }
+       
+       uint64_t                reserved4() const                                       INLINE { return P::getP(routines.fields.reserved4); }
+       void                    set_reserved4(uint64_t value)           INLINE { P::setP(routines.fields.reserved4, value); }
+       
+       uint64_t                reserved5() const                                       INLINE { return P::getP(routines.fields.reserved5); }
+       void                    set_reserved5(uint64_t value)           INLINE { P::setP(routines.fields.reserved5, value); }
+       
+       uint64_t                reserved6() const                                       INLINE { return P::getP(routines.fields.reserved6); }
+       void                    set_reserved6(uint64_t value)           INLINE { P::setP(routines.fields.reserved6, value); }
+       
+       typedef typename P::E           E;
+       enum {
+               CMD = macho_routines_content<P>::CMD
+       };
+private:
+       macho_routines_content<P>       routines;
+};
+
+
+//
+// mach-o symbol table load command
+//
+template <typename P>
+class macho_symtab_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                symoff() const                          INLINE { return E::get32(fields.symoff); }
+       void                    set_symoff(uint32_t value)      INLINE { E::set32(fields.symoff, value);  }
+       
+       uint32_t                nsyms() const                           INLINE { return E::get32(fields.nsyms); }
+       void                    set_nsyms(uint32_t value)       INLINE { E::set32(fields.nsyms, value);  }
+       
+       uint32_t                stroff() const                          INLINE { return E::get32(fields.stroff); }
+       void                    set_stroff(uint32_t value)      INLINE { E::set32(fields.stroff, value);  }
+       
+       uint32_t                strsize() const                         INLINE { return E::get32(fields.strsize); }
+       void                    set_strsize(uint32_t value)     INLINE { E::set32(fields.strsize, value);  }
+       
+       
+       typedef typename P::E           E;
+private:
+       symtab_command  fields;
+};
+
+
+//
+// mach-o dynamic symbol table load command
+//
+template <typename P>
+class macho_dysymtab_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                ilocalsym() const                                       INLINE { return E::get32(fields.ilocalsym); }
+       void                    set_ilocalsym(uint32_t value)           INLINE { E::set32(fields.ilocalsym, value);  }
+       
+       uint32_t                nlocalsym() const                                       INLINE { return E::get32(fields.nlocalsym); }
+       void                    set_nlocalsym(uint32_t value)           INLINE { E::set32(fields.nlocalsym, value);  }
+       
+       uint32_t                iextdefsym() const                                      INLINE { return E::get32(fields.iextdefsym); }
+       void                    set_iextdefsym(uint32_t value)          INLINE { E::set32(fields.iextdefsym, value);  }
+       
+       uint32_t                nextdefsym() const                                      INLINE { return E::get32(fields.nextdefsym); }
+       void                    set_nextdefsym(uint32_t value)          INLINE { E::set32(fields.nextdefsym, value);  }
+       
+       uint32_t                iundefsym() const                                       INLINE { return E::get32(fields.iundefsym); }
+       void                    set_iundefsym(uint32_t value)           INLINE { E::set32(fields.iundefsym, value);  }
+       
+       uint32_t                nundefsym() const                                       INLINE { return E::get32(fields.nundefsym); }
+       void                    set_nundefsym(uint32_t value)           INLINE { E::set32(fields.nundefsym, value);  }
+       
+       uint32_t                tocoff() const                                          INLINE { return E::get32(fields.tocoff); }
+       void                    set_tocoff(uint32_t value)                      INLINE { E::set32(fields.tocoff, value);  }
+       
+       uint32_t                ntoc() const                                            INLINE { return E::get32(fields.ntoc); }
+       void                    set_ntoc(uint32_t value)                        INLINE { E::set32(fields.ntoc, value);  }
+       
+       uint32_t                modtaboff() const                                       INLINE { return E::get32(fields.modtaboff); }
+       void                    set_modtaboff(uint32_t value)           INLINE { E::set32(fields.modtaboff, value);  }
+       
+       uint32_t                nmodtab() const                                         INLINE { return E::get32(fields.nmodtab); }
+       void                    set_nmodtab(uint32_t value)                     INLINE { E::set32(fields.nmodtab, value);  }
+       
+       uint32_t                extrefsymoff() const                            INLINE { return E::get32(fields.extrefsymoff); }
+       void                    set_extrefsymoff(uint32_t value)        INLINE { E::set32(fields.extrefsymoff, value);  }
+       
+       uint32_t                nextrefsyms() const                                     INLINE { return E::get32(fields.nextrefsyms); }
+       void                    set_nextrefsyms(uint32_t value)         INLINE { E::set32(fields.nextrefsyms, value);  }
+       
+       uint32_t                indirectsymoff() const                          INLINE { return E::get32(fields.indirectsymoff); }
+       void                    set_indirectsymoff(uint32_t value)      INLINE { E::set32(fields.indirectsymoff, value);  }
+       
+       uint32_t                nindirectsyms() const                           INLINE { return E::get32(fields.nindirectsyms); }
+       void                    set_nindirectsyms(uint32_t value)       INLINE { E::set32(fields.nindirectsyms, value);  }
+       
+       uint32_t                extreloff() const                                       INLINE { return E::get32(fields.extreloff); }
+       void                    set_extreloff(uint32_t value)           INLINE { E::set32(fields.extreloff, value);  }
+       
+       uint32_t                nextrel() const                                         INLINE { return E::get32(fields.nextrel); }
+       void                    set_nextrel(uint32_t value)                     INLINE { E::set32(fields.nextrel, value);  }
+       
+       uint32_t                locreloff() const                                       INLINE { return E::get32(fields.locreloff); }
+       void                    set_locreloff(uint32_t value)           INLINE { E::set32(fields.locreloff, value);  }
+       
+       uint32_t                nlocrel() const                                         INLINE { return E::get32(fields.nlocrel); }
+       void                    set_nlocrel(uint32_t value)                     INLINE { E::set32(fields.nlocrel, value);  }
+       
+       typedef typename P::E           E;
+private:
+       dysymtab_command        fields;
+};
+
+
+//
+// mach-o two-level hints load command
+//
+template <typename P>
+class macho_twolevel_hints_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                offset() const                          INLINE { return E::get32(fields.offset); }
+       void                    set_offset(uint32_t value)      INLINE { E::set32(fields.offset, value);  }
+       
+       uint32_t                nhints() const                          INLINE { return E::get32(fields.nhints); }
+       void                    set_nhints(uint32_t value)      INLINE { E::set32(fields.nhints, value);  }
+       
+       typedef typename P::E           E;
+private:
+       twolevel_hints_command  fields;
+};
+
+
+//
+// mach-o threads load command
+//
+template <typename P>
+class macho_thread_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                flavor() const                                                                          INLINE { return E::get32(fields_flavor); }
+       void                    set_flavor(uint32_t value)                                                      INLINE { E::set32(fields_flavor, value);  }
+       
+       uint32_t                count() const                                                                           INLINE { return E::get32(fields_count); }
+       void                    set_count(uint32_t value)                                                       INLINE { E::set32(fields_count, value);  }
+       
+       uint64_t                thread_register(uint32_t index) const                           INLINE { return P::getP(thread_registers[index]); }
+       void                    set_thread_register(uint32_t index, uint64_t value)     INLINE { P::setP(thread_registers[index], value); }
+       
+       typedef typename P::E           E;
+       typedef typename P::uint_t      pint_t;
+private:
+       struct thread_command   fields;
+       uint32_t                                fields_flavor;
+       uint32_t                                fields_count;
+       pint_t                                  thread_registers[1];
+};
+
+
+//
+// mach-o misc data 
+//
+template <typename P>
+class macho_linkedit_data_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                dataoff() const                         INLINE { return E::get32(fields.dataoff); }
+       void                    set_dataoff(uint32_t value)     INLINE { E::set32(fields.dataoff, value);  }
+       
+       uint32_t                datasize() const                        INLINE { return E::get32(fields.datasize); }
+       void                    set_datasize(uint32_t value)INLINE { E::set32(fields.datasize, value);  }
+       
+       
+       typedef typename P::E           E;
+private:
+       linkedit_data_command   fields;
+};
+
+
+//
+// mach-o symbol table entry 
+//
+template <typename P> struct macho_nlist_content {};
+template <> struct macho_nlist_content<Pointer32<BigEndian> >    { struct nlist                fields; };
+template <> struct macho_nlist_content<Pointer64<BigEndian> >   { struct nlist_64      fields; };
+template <> struct macho_nlist_content<Pointer32<LittleEndian> > { struct nlist                fields; };
+template <> struct macho_nlist_content<Pointer64<LittleEndian> > { struct nlist_64     fields; };
+
+template <typename P>
+class macho_nlist {
+public:
+       uint32_t                n_strx() const                                  INLINE { return E::get32(entry.fields.n_un.n_strx); }
+       void                    set_n_strx(uint32_t value)              INLINE { E::set32((uint32_t&)entry.fields.n_un.n_strx, value); }
+
+       uint8_t                 n_type() const                                  INLINE { return entry.fields.n_type; }
+       void                    set_n_type(uint8_t value)               INLINE { entry.fields.n_type = value; }
+
+       uint8_t                 n_sect() const                                  INLINE { return entry.fields.n_sect; }
+       void                    set_n_sect(uint8_t value)               INLINE { entry.fields.n_sect = value; }
+
+       uint16_t                n_desc() const                                  INLINE { return E::get16(entry.fields.n_desc); }
+       void                    set_n_desc(uint16_t value)              INLINE { E::set16((uint16_t&)entry.fields.n_desc, value); }
+
+       uint64_t                n_value() const                                 INLINE { return P::getP(entry.fields.n_value); }
+       void                    set_n_value(uint64_t value)             INLINE { P::setP(entry.fields.n_value, value); }
+
+       typedef typename P::E           E;
+private:
+       macho_nlist_content<P>  entry;
+};
+
+
+
+//
+// mach-o relocation info
+//
+template <typename P>
+class macho_relocation_info {
+public:
+       uint32_t                r_address() const                               INLINE { return E::get32(address); }
+       void                    set_r_address(uint32_t value)   INLINE { E::set32(address, value); }
+
+       uint32_t                r_symbolnum() const                             INLINE { return E::getBits(other, 0, 24); }
+       void                    set_r_symbolnum(uint32_t value) INLINE { E::setBits(other, value, 0, 24); }
+
+       bool                    r_pcrel() const                                 INLINE { return E::getBits(other, 24, 1); }
+       void                    set_r_pcrel(bool value)                 INLINE { E::setBits(other, value, 24, 1); }     
+       
+       uint8_t                 r_length() const                                INLINE { return E::getBits(other, 25, 2); }
+       void                    set_r_length(uint8_t value)             INLINE { E::setBits(other, value, 25, 2); }
+       
+       bool                    r_extern() const                                INLINE { return E::getBits(other, 27, 1); }
+       void                    set_r_extern(bool value)                INLINE { E::setBits(other, value, 27, 1); }
+       
+       uint8_t                 r_type() const                                  INLINE { return E::getBits(other, 28, 4); }
+       void                    set_r_type(uint8_t value)               INLINE { E::setBits(other, value, 28, 4); }
+               
+       void                    set_r_length()                                  INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); }
+
+       typedef typename P::E           E;
+private:
+       uint32_t                address;
+       uint32_t                other;
+};
+
+
+//
+// mach-o scattered relocation info
+// The bit fields are always in big-endian order (see mach-o/reloc.h)
+//
+template <typename P>
+class macho_scattered_relocation_info {
+public:
+       bool                    r_scattered() const                     INLINE { return BigEndian::getBitsRaw(E::get32(other), 0, 1); }
+       void                    set_r_scattered(bool x)         INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 0, 1);  E::set32(other, temp); }
+
+       bool                    r_pcrel() const                         INLINE { return BigEndian::getBitsRaw(E::get32(other), 1, 1); }
+       void                    set_r_pcrel(bool x)                     INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 1, 1);  E::set32(other, temp); }
+
+       uint8_t                 r_length() const                        INLINE { return BigEndian::getBitsRaw(E::get32(other), 2, 2); }
+       void                    set_r_length(uint8_t x)         INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 2, 2);  E::set32(other, temp); }
+
+       uint8_t                 r_type() const                          INLINE { return BigEndian::getBitsRaw(E::get32(other), 4, 4); }
+       void                    set_r_type(uint8_t x)           INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 4, 4);  E::set32(other, temp); }
+
+       uint32_t                r_address() const                       INLINE { return BigEndian::getBitsRaw(E::get32(other), 8, 24); }
+       void                    set_r_address(uint32_t x)       INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 8, 24);  E::set32(other, temp); }
+
+       uint32_t                r_value() const                         INLINE { return E::get32(value); }
+       void                    set_r_value(uint32_t x)         INLINE { E::set32(value, x); }
+
+       uint32_t                r_other() const                         INLINE { return other; }
+       
+       typedef typename P::E           E;
+private:
+       uint32_t                other;
+       uint32_t                value;
+};
+
+
+
+
+
+
+#endif // __MACH_O_FILE_ABSTRACTION__
+
+
diff --git a/launch-cache/MachOLayout.hpp b/launch-cache/MachOLayout.hpp
new file mode 100644 (file)
index 0000000..1a3017f
--- /dev/null
@@ -0,0 +1,463 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+
+#ifndef __MACHO_LAYOUT__
+#define __MACHO_LAYOUT__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+#include <vector>
+#include <set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+void throwf(const char* format, ...) __attribute__((format(printf, 1, 2)));
+
+__attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+
+class MachOLayoutAbstraction
+{
+public:
+       struct Segment
+       {
+       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),
+                                                       fNewAddress(0), fMappedAddress(NULL) {
+                                                               strlcpy(fName, segName, 16);
+                                                       }
+                                                       
+               uint64_t        address() const         { return fAddress; }
+               uint64_t        size() const            { return fSize; }
+               uint64_t        fileOffset() const      { return fFileOffset; }
+               uint64_t        fileSize() const        { return fFileSize; }
+               uint32_t        permissions() const { return fPermissions; }
+               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; }
+               uint64_t        newAddress() const      { return fNewAddress; }
+               void*           mappedAddress() const                   { return fMappedAddress; }
+               void            setNewAddress(uint64_t addr)    { fNewAddress = addr; }
+               void            setMappedAddress(void* addr)    { fMappedAddress = addr; }
+               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 writable)              { if (writable) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
+       private:
+               uint64_t        fAddress;
+               uint64_t        fSize;
+               uint64_t        fFileOffset;
+               uint64_t        fFileSize;
+               uint64_t        fNewAddress;
+               void*           fMappedAddress;
+               uint32_t        fPermissions;
+               char            fName[16];
+       };
+
+       struct Library
+       {
+               const char*     name;
+               uint32_t        currentVersion;
+               uint32_t        compatibilityVersion;
+       };
+       
+       
+       virtual cpu_type_t                                                      getArchitecture() const = 0;
+       virtual const char*                                                     getFilePath() const = 0;
+       virtual uint64_t                                                        getOffsetInUniversalFile() const        = 0;
+       virtual uint32_t                                                        getFileType() const     = 0;
+       virtual uint32_t                                                        getFlags() const = 0;
+       virtual Library                                                         getID() const = 0;
+       virtual bool                                                            isSplitSeg() const = 0;
+       virtual bool                                                            hasSplitSegInfo() const = 0;
+       virtual uint32_t                                                        getNameFileOffset() const = 0;
+       virtual time_t                                                          getLastModTime() const = 0;
+       virtual ino_t                                                           getInode() const = 0;
+       virtual std::vector<Segment>&                           getSegments() = 0;
+       virtual const std::vector<Segment>&                     getSegments() const = 0;
+       virtual const std::vector<Library>&                     getLibraries() const = 0;
+       virtual uint64_t                                                        getBaseAddress() const = 0;
+       virtual uint64_t                                                        getVMSize() const = 0;
+       virtual uint64_t                                                        getBaseExecutableAddress() const = 0;
+       virtual uint64_t                                                        getBaseWritableAddress() const = 0;
+       virtual uint64_t                                                        getBaseReadOnlyAddress() const = 0;
+       virtual uint64_t                                                        getExecutableVMSize() const = 0;
+       virtual uint64_t                                                        getWritableVMSize() const = 0;
+       virtual uint64_t                                                        getReadOnlyVMSize() const = 0;
+};
+
+
+
+
+template <typename A>
+class MachOLayout : public MachOLayoutAbstraction
+{
+public:
+                                                                                               MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime);
+       virtual                                                                         ~MachOLayout() {}
+
+       virtual cpu_type_t                                                      getArchitecture() const;
+       virtual const char*                                                     getFilePath() const             { return fPath; }
+       virtual uint64_t                                                        getOffsetInUniversalFile() const { return fOffset; }
+       virtual uint32_t                                                        getFileType() const             { return fFileType; }
+       virtual uint32_t                                                        getFlags() const                { return fFlags; }
+       virtual Library                                                         getID() const                   { return fDylibID; }
+       virtual bool                                                            isSplitSeg() const;
+       virtual bool                                                            hasSplitSegInfo() const { return fHasSplitSegInfo; }
+       virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
+       virtual time_t                                                          getLastModTime() const  { return fMTime; }
+       virtual ino_t                                                           getInode() const                { return fInode; }
+       virtual std::vector<Segment>&                           getSegments()                   { return fSegments; }
+       virtual const std::vector<Segment>&                     getSegments() const             { return fSegments; }
+       virtual const std::vector<Library>&                     getLibraries() const    { return fLibraries; }
+       virtual uint64_t                                                        getBaseAddress() const  { return fLowSegment->address(); }
+       virtual uint64_t                                                        getVMSize() const               { return fVMSize; }
+       virtual uint64_t                                                        getBaseExecutableAddress() const { return fLowExecutableSegment->address(); }
+       virtual uint64_t                                                        getBaseWritableAddress() const  { return fLowWritableSegment->address(); }
+       virtual uint64_t                                                        getBaseReadOnlyAddress() const  { return fLowReadOnlySegment->address(); }
+       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;
+       
+       const char*                                                                     fPath;
+       uint64_t                                                                        fOffset;
+       uint32_t                                                                        fFileType;
+       uint32_t                                                                        fFlags;
+       std::vector<Segment>                                            fSegments;
+       std::vector<Library>                                            fLibraries;
+       const Segment*                                                          fLowSegment;
+       const Segment*                                                          fLowExecutableSegment;
+       const Segment*                                                          fLowWritableSegment;
+       const Segment*                                                          fLowReadOnlySegment;
+       Library                                                                         fDylibID;
+       uint32_t                                                                        fNameFileOffset;
+       time_t                                                                          fMTime;
+       ino_t                                                                           fInode;
+       uint64_t                                                                        fVMSize;
+       uint64_t                                                                        fVMExecutableSize;
+       uint64_t                                                                        fVMWritablSize;
+       uint64_t                                                                        fVMReadOnlySize;
+       bool                                                                            fHasSplitSegInfo;
+};
+
+
+
+class UniversalMachOLayout
+{
+public:
+                                                                                               UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* 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; }
+
+private:
+       struct CStringEquals {
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, const UniversalMachOLayout*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
+
+       static PathToNode                                                       fgLayoutCache;
+       const char*                                                                     fPath;
+       std::vector<MachOLayoutAbstraction*>            fLayouts;
+};
+
+UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
+
+
+const MachOLayoutAbstraction* UniversalMachOLayout::getArch(cpu_type_t arch) const
+{
+       for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
+               const MachOLayoutAbstraction* layout = *it;
+               if ( layout->getArchitecture() == arch ) 
+                       return layout;
+       }
+       return NULL;
+}
+
+const UniversalMachOLayout* UniversalMachOLayout::find(const char* path, const std::set<cpu_type_t>* onlyArchs)
+{
+       // look in cache
+       PathToNode::iterator pos = fgLayoutCache.find(path);
+       if ( pos != fgLayoutCache.end() )
+               return pos->second;
+               
+       // create UniversalMachOLayout
+       const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs);
+       
+       // add it to cache
+       fgLayoutCache[result->fPath] = result;
+       
+       return result;
+}
+
+
+UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* onlyArchs)
+ : fPath(strdup(path))
+{
+       // map in whole file
+       int fd = ::open(path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("can't open file, errno=%d", errno);
+       struct stat stat_buf;
+       if ( fstat(fd, &stat_buf) == -1)
+               throwf("can't stat open file %s, errno=%d", path, errno);
+       if ( stat_buf.st_size < 20 )
+               throwf("file too small %s", path);
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( p == (uint8_t*)(-1) )
+               throwf("can't map file %s, errno=%d", path, errno);
+       ::close(fd);
+
+       try {
+               // if fat file, process each architecture
+               const fat_header* fh = (fat_header*)p;
+               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);
+                               try {
+                                       if ( (onlyArchs == NULL) || (onlyArchs->count(curArch) != 0) ) {
+                                               switch ( curArch ) {
+                                                       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));
+                                                               break;
+                                                       case CPU_TYPE_I386:
+                                                               fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               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));
+                                                               break;
+                                                       default:
+                                                               throw "unknown file format";
+                                               }
+                                       }
+                               }
+                               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));
+                               }
+                               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));
+                               }
+                               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));
+                               }
+                               else {
+                                       throw "unknown file format";
+                               }
+                       }
+                       catch (const char* msg) {
+                               fprintf(stderr, "warning: %s for %s\n", msg, path);
+                       }
+               }
+       }
+       catch (...) {
+               ::munmap(p, stat_buf.st_size);
+               throw;
+       }
+}
+
+
+
+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)
+{
+       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";
+       switch ( mh->filetype() ) {
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_EXECUTE:
+               case MH_DYLIB_STUB:
+               case MH_DYLINKER:
+                       break;
+               default:
+                       throw "file is not a mach-o final linked image";
+       }
+       fFlags = mh->flags();
+       fFileType = mh->filetype();
+       
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
+       const uint32_t cmd_count = mh->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch ( cmd->cmd() ) {
+                       case LC_ID_DYLIB:       
+                               {
+                                       macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                                       fDylibID.name = strdup(dylib->name());
+                                       fDylibID.currentVersion = dylib->current_version();
+                                       fDylibID.compatibilityVersion = dylib->compatibility_version();
+                                       fNameFileOffset = dylib->name() - (char*)machHeader;
+                               }
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                               {
+                                       macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
+                                       Library lib;
+                                       lib.name = strdup(dylib->name());
+                                       lib.currentVersion = dylib->current_version();
+                                       lib.compatibilityVersion = dylib->compatibility_version();
+                                       fLibraries.push_back(lib);
+                               }
+                               break;
+                       case LC_SEGMENT_SPLIT_INFO:
+                               fHasSplitSegInfo = true;
+                               break;
+                       case macho_segment_command<P>::CMD:
+                               {
+                                       macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
+                                       fSegments.push_back(Segment(segCmd->vmaddr(), segCmd->vmsize(), segCmd->fileoff(), 
+                                                               segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+
+       fLowSegment = NULL;
+       fLowExecutableSegment = NULL;
+       fLowWritableSegment = NULL;
+       fLowReadOnlySegment = NULL;
+       fVMExecutableSize = 0;
+       fVMWritablSize = 0;
+       fVMReadOnlySize = 0;
+       fVMSize = 0;
+       const Segment* highSegment = NULL;
+       for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
+               const Segment& seg = *it;
+               if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) )
+                       fLowSegment = &seg;
+               if ( (highSegment == NULL) || (seg.address() > highSegment->address()) )
+                       highSegment = &seg;
+               if ( seg.executable() ) {
+                       if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) )
+                               fLowExecutableSegment = &seg;
+                       fVMExecutableSize += seg.size();
+               }
+               else if ( seg.writable()) {
+                       if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) )
+                               fLowWritableSegment = &seg;
+                       fVMWritablSize += seg.size();
+               }
+               else {
+                       if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
+                               fLowReadOnlySegment = &seg;
+                       fVMReadOnlySize += seg.size();
+               }
+       }
+       if ( (highSegment != NULL) && (fLowSegment != NULL) )
+               fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
+}
+
+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 <>
+bool MachOLayout<ppc>::isSplitSeg() const
+{
+       return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
+}
+
+template <>
+bool MachOLayout<x86>::isSplitSeg() const
+{
+       return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
+}
+
+template <typename A>
+bool MachOLayout<A>::isSplitSeg() const
+{
+       return false;
+}
+
+
+#endif // __MACHO_LAYOUT__
+
+
+
diff --git a/launch-cache/MachORebaser.hpp b/launch-cache/MachORebaser.hpp
new file mode 100644 (file)
index 0000000..4cf81f3
--- /dev/null
@@ -0,0 +1,812 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+
+#ifndef __MACHO_REBASER__
+#define __MACHO_REBASER__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/x86_64/reloc.h>
+#include <vector>
+#include <set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "MachOLayout.hpp"
+
+
+
+class AbstractRebaser
+{
+public:
+       virtual cpu_type_t                                                      getArchitecture() const = 0;
+       virtual uint64_t                                                        getBaseAddress() const = 0;
+       virtual uint64_t                                                        getVMSize() const = 0;
+       virtual void                                                            rebase() = 0;
+};
+
+
+template <typename A>
+class Rebaser : public AbstractRebaser
+{
+public:
+                                                                                               Rebaser(const MachOLayoutAbstraction&);
+       virtual                                                                         ~Rebaser() {}
+
+       virtual cpu_type_t                                                      getArchitecture() const;
+       virtual uint64_t                                                        getBaseAddress() const;
+       virtual uint64_t                                                        getVMSize() const;
+       virtual void                                                            rebase();
+
+protected:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+               
+       pint_t*                                                                         mappedAddressForNewAddress(pint_t vmaddress);
+       pint_t                                                                          getSlideForNewAddress(pint_t newAddress);
+       
+private:
+       pint_t                                                                          calculateRelocBase();
+       void                                                                            adjustLoadCommands();
+       void                                                                            adjustSymbolTable();
+       void                                                                            adjustDATA();
+       void                                                                            adjustCode();
+       void                                                                            adjustSegmentLoadCommand(macho_segment_command<P>* seg);
+       pint_t                                                                          getSlideForVMAddress(pint_t vmaddress);
+       pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
+       pint_t*                                                                         mappedAddressForRelocAddress(pint_t r_address);
+       void                                                                            adjustRelocBaseAddresses();
+       const uint8_t*                                                          doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta);
+       void                                                                            doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta);
+       void                                                                            doLocalRelocation(const macho_relocation_info<P>* reloc);
+       bool                                                                            unequalSlides() const;
+
+protected:     
+       const macho_header<P>*                                          fHeader; 
+       uint8_t*                                                                        fLinkEditBase;                          // add file offset to this to get linkedit content
+       const MachOLayoutAbstraction&                           fLayout;
+private:
+       pint_t                                                                          fOrignalVMRelocBaseAddress; // add reloc address to this to get original address reloc referred to
+       bool                                                                            fSplittingSegments;
+};
+
+
+
+template <typename A>
+Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
+ :     fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL), fSplittingSegments(false)
+{
+       fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
+       switch ( fHeader->filetype() ) {
+               case MH_DYLIB:
+               case MH_BUNDLE:
+                       break;
+               default:
+                       throw "file is not a dylib or bundle";
+       }
+       
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( strcmp(seg.name(), "__LINKEDIT") == 0 ) {
+                       fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
+                       break;
+               }
+       }
+       if ( fLinkEditBase == NULL )    
+               throw "no __LINKEDIT segment";
+               
+       fOrignalVMRelocBaseAddress = 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 <typename A>
+bool Rebaser<A>::unequalSlides() const
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       uint64_t slide = segments[0].newAddress() - segments[0].address();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( (seg.newAddress() - seg.address()) != slide )
+                       return true;
+       }
+       return false;
+}
+
+template <typename A>
+uint64_t Rebaser<A>::getBaseAddress() const
+{
+       return fLayout.getSegments()[0].address();
+}
+
+template <typename A>
+uint64_t Rebaser<A>::getVMSize() const
+{
+       uint64_t highestVMAddress = 0;
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( seg.address() > highestVMAddress )
+                       highestVMAddress = seg.address();
+       }
+       return (((highestVMAddress - getBaseAddress()) + 4095) & (-4096));
+}
+
+
+
+template <typename A>
+void Rebaser<A>::rebase()
+{              
+       // update writable segments that have internal pointers
+       this->adjustDATA();
+
+       // if splitting segments, update code-to-data references
+       this->adjustCode();
+       
+       // change address on relocs now that segments are split
+       this->adjustRelocBaseAddresses();
+       
+       // update load commands
+       this->adjustLoadCommands();
+       
+       // update symbol table  
+       this->adjustSymbolTable();
+}
+
+template <>
+void Rebaser<x86>::adjustSegmentLoadCommand(macho_segment_command<P>* seg)
+{
+       // __IMPORT segments are not-writable in shared cache
+       if ( strcmp(seg->segname(), "__IMPORT") == 0 ) 
+               seg->set_initprot(VM_PROT_READ|VM_PROT_EXECUTE);
+}
+
+template <typename A>
+void Rebaser<A>::adjustSegmentLoadCommand(macho_segment_command<P>* seg)
+{
+}
+
+
+template <typename A>
+void Rebaser<A>::adjustLoadCommands()
+{
+       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_ID_DYLIB:
+                               if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+                                       // clear timestamp so that any prebound clients are invalidated
+                                       macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                                       dylib->set_timestamp(1);
+                               }
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                               if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+                                       // clear expected timestamps so that this image will load with invalid prebinding 
+                                       macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                                       dylib->set_timestamp(2);
+                               }
+                               break;
+                       case macho_routines_command<P>::CMD:
+                               // update -init command
+                               {
+                                       struct macho_routines_command<P>* routines = (struct macho_routines_command<P>*)cmd;
+                                       routines->set_init_address(routines->init_address() + this->getSlideForVMAddress(routines->init_address()));
+                               }
+                               break;
+                       case macho_segment_command<P>::CMD:
+                               // update segment commands
+                               {
+                                       macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                                       this->adjustSegmentLoadCommand(seg);
+                                       pint_t slide = this->getSlideForVMAddress(seg->vmaddr());
+                                       seg->set_vmaddr(seg->vmaddr() + slide);
+                                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                                       macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                                               sect->set_addr(sect->addr() + slide);
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+
+template <typename A>
+typename A::P::uint_t Rebaser<A>::getSlideForVMAddress(pint_t vmaddress)
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( (seg.address() <= vmaddress) && (seg.size() != 0) && ((vmaddress < (seg.address()+seg.size())) || (seg.address() == vmaddress)) ) {
+                       return seg.newAddress() - seg.address();
+               }
+       }
+       throwf("vm address 0x%08llX not found", (uint64_t)vmaddress);
+}
+
+
+template <typename A>
+typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(pint_t vmaddress)
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( (seg.address() <= vmaddress) && (vmaddress < (seg.address()+seg.size())) ) {
+                       return (pint_t*)((vmaddress - seg.address()) + (uint8_t*)seg.mappedAddress());
+               }
+       }
+       throwf("mappedAddressForVMAddress(0x%08llX) not found", (uint64_t)vmaddress);
+}
+
+template <typename A>
+typename A::P::uint_t* Rebaser<A>::mappedAddressForNewAddress(pint_t vmaddress)
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( (seg.newAddress() <= vmaddress) && (vmaddress < (seg.newAddress()+seg.size())) ) {
+                       return (pint_t*)((vmaddress - seg.newAddress()) + (uint8_t*)seg.mappedAddress());
+               }
+       }
+       throwf("mappedAddressForNewAddress(0x%08llX) not found", (uint64_t)vmaddress);
+}
+
+template <typename A>
+typename A::P::uint_t Rebaser<A>::getSlideForNewAddress(pint_t newAddress)
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( (seg.newAddress() <= newAddress) && (newAddress < (seg.newAddress()+seg.size())) ) {
+                       return seg.newAddress() - seg.address();
+               }
+       }
+       throwf("new address 0x%08llX not found", (uint64_t)newAddress);
+}
+
+template <typename A>
+typename A::P::uint_t* Rebaser<A>::mappedAddressForRelocAddress(pint_t r_address)
+{
+       return this->mappedAddressForVMAddress(r_address + fOrignalVMRelocBaseAddress);
+}
+
+
+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());
+       }       
+
+       // 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) {
+               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) {
+               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>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta)
+{
+       //fprintf(stderr, "doCodeUpdate(kind=%d, address=0x%0llX, dataDelta=0x%08llX, importDelta=0x%08llX)\n", kind, address, codeToDataDelta, codeToImportDelta);
+       uint32_t* p;
+       uint32_t instruction;
+       uint32_t value;
+       uint64_t value64;
+       switch (kind) {
+               case 1: // 32-bit pointer
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       value = A::P::E::get32(*p);
+                       value += codeToDataDelta;
+                        A::P::E::set32(*p, value);
+                       break;
+               case 2: // 64-bit pointer
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       value64 =  A::P::E::get64(*(uint64_t*)p);
+                       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
+                       // 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);
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       instruction = BigEndian::get32(*p);
+                       uint16_t originalLo16 = instruction & 0x0000FFFF;
+                       uint16_t delta64Ks = codeToDataDelta >> 16;
+                       instruction = (instruction & 0xFFFF0000) | ((originalLo16+delta64Ks) & 0x0000FFFF);
+                       BigEndian::set32(*p, instruction);
+                       break;
+               case 4: // only used for i386, a reference to something in the IMPORT segment
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       value = A::P::E::get32(*p);
+                       value += codeToImportDelta;
+                        A::P::E::set32(*p, value);
+                       break;
+               default:
+                       throwf("invalid kind=%d in split seg info", kind);
+       }
+}
+
+template <typename A>
+const uint8_t* Rebaser<A>::doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta)
+{
+       uint64_t address = 0;
+       uint64_t delta = 0;
+       uint32_t shift = 0;
+       bool more = true;
+       do {
+               uint8_t byte = *p++;
+               delta |= ((byte & 0x7F) << shift);
+               shift += 7;
+               if ( byte < 0x80 ) {
+                       if ( delta != 0 ) {
+                               address += delta;
+                               doCodeUpdate(kind, address+orgBaseAddress, codeToDataDelta, codeToImportDelta);
+                               delta = 0;
+                               shift = 0;
+                       }
+                       else {
+                               more = false;
+                       }
+               }
+       } while (more);
+       return p;
+}
+
+template <typename A>
+void Rebaser<A>::adjustCode()
+{
+       if ( fSplittingSegments ) {
+               // get uleb128 compressed runs of code addresses to update
+               const uint8_t* infoStart = NULL;
+               const uint8_t* infoEnd = 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_SEGMENT_SPLIT_INFO:
+                                       {
+                                               const macho_linkedit_data_command<P>* segInfo = (macho_linkedit_data_command<P>*)cmd;
+                                               infoStart = &fLinkEditBase[segInfo->dataoff()];
+                                               infoEnd = &infoStart[segInfo->datasize()];
+                                       }
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+               }
+               // calculate how much we need to slide writable segments
+               const uint64_t orgBaseAddress = this->getBaseAddress();
+               int64_t codeToDataDelta = 0;
+               int64_t codeToImportDelta = 0;
+               const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+               const MachOLayoutAbstraction::Segment& codeSeg = segments[0];
+               for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+                       const MachOLayoutAbstraction::Segment& dataSeg = *it;
+                       if ( strcmp(dataSeg.name(), "__IMPORT") == 0 )
+                               codeToImportDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
+                       else if ( dataSeg.writable() ) 
+                               codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
+               }
+               // decompress and call doCodeUpdate() on each address
+               for(const uint8_t* p = infoStart; *p != 0;) {
+                       uint8_t kind = *p++;
+                       p = this->doCodeUpdateForEachULEB128Address(p, kind, orgBaseAddress, codeToDataDelta, codeToImportDelta);
+               }
+       }
+}
+
+
+template <typename A>
+void Rebaser<A>::adjustDATA()
+{
+       const macho_dysymtab_command<P>* dysymtab = 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_DYSYMTAB:
+                               dysymtab = (macho_dysymtab_command<P>*)cmd;
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+
+
+       // 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()];
+       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;
+       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()]);
+                       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();
+                                       uint32_t pointerCount = sect->size() / sizeof(pint_t);
+                                       pint_t* nonLazyPointerAddr = this->mappedAddressForVMAddress(sect->addr());
+                                       for (uint32_t j=0; j < pointerCount; ++j, ++nonLazyPointerAddr) {
+                                               if ( E::get32(indirectTable[indirectTableOffset + j]) == INDIRECT_SYMBOL_LOCAL ) {
+                                                       pint_t value = A::P::getP(*nonLazyPointerAddr);
+                                                       P::setP(*nonLazyPointerAddr, value + this->getSlideForVMAddress(value));
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+}
+
+
+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());
+               }       
+
+               // get amount to adjust reloc address
+               int32_t relocAddressAdjust = 0;
+               const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+               for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+                       const MachOLayoutAbstraction::Segment& seg = *it;
+                       if ( seg.writable() ) {
+                               relocAddressAdjust = seg.address() - segments[0].address();
+                               break;
+                       }
+               }
+
+               // 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()];
+               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()];
+               for (macho_relocation_info<P>* reloc=externRelocsStart; reloc < externRelocsEnd; ++reloc) {
+                       reloc->set_r_address(reloc->r_address()-relocAddressAdjust);
+               }
+       }
+}
+
+template <>
+void Rebaser<x86_64>::adjustRelocBaseAddresses()
+{
+       // x86_64 already have reloc base of first writable segment
+}
+
+
+template <>
+void Rebaser<x86_64>::doLocalRelocation(const macho_relocation_info<x86_64::P>* reloc)
+{
+       if ( reloc->r_type() == X86_64_RELOC_UNSIGNED ) {
+               pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
+               pint_t value = P::getP(*addr);
+               P::setP(*addr, value + this->getSlideForVMAddress(value));
+       }
+       else {
+               throw "invalid relocation type";
+       }
+}
+
+template <>
+void Rebaser<ppc>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
+                       pint_t value = P::getP(*addr);
+                       P::setP(*addr, value + this->getSlideForVMAddress(value));
+               }
+       }
+       else {
+               macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               if ( sreloc->r_type() == PPC_RELOC_PB_LA_PTR ) {
+                       sreloc->set_r_value( sreloc->r_value() + this->getSlideForVMAddress(sreloc->r_value()) );
+               }
+               else {
+                       throw "cannot rebase final linked image with scattered relocations";
+               }
+       }
+}
+
+template <>
+void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
+                       pint_t value = P::getP(*addr);
+                       P::setP(*addr, value + this->getSlideForVMAddress(value));
+               }
+       }
+       else {
+               macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               if ( sreloc->r_type() == GENERIC_RELOC_PB_LA_PTR ) {
+                       sreloc->set_r_value( sreloc->r_value() + this->getSlideForVMAddress(sreloc->r_value()) );
+               }
+               else {
+                       throw "cannot rebase final linked image with scattered relocations";
+               }
+       }
+}
+
+template <typename A>
+void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
+                       pint_t value = P::getP(*addr);
+                       P::setP(*addr, value + this->getSlideForVMAddress(value));
+               }
+       }
+       else {
+               throw "cannot rebase final linked image with scattered relocations";
+       }
+}
+
+
+template <typename A>
+typename A::P::uint_t Rebaser<A>::calculateRelocBase()
+{
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       if ( fHeader->flags() & MH_SPLIT_SEGS ) {
+               // reloc addresses are from the start of the first writable segment
+               for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+                       const MachOLayoutAbstraction::Segment& seg = *it;
+                       if ( seg.writable() ) {
+                               // found first writable segment
+                               return seg.address();
+                       }
+               }
+               throw "no writable segment";
+       }
+       else {
+               // reloc addresses are from the start of the mapped file (base address)
+               return segments[0].address();
+       }
+}
+
+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()
+{
+       // reloc addresses are always based from the start of the first writable segment
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( seg.writable() ) {
+                       // found first writable segment
+                       return seg.address();
+               }
+       }
+       throw "no writable segment";
+}
+
+
+#if 0
+class MultiArchRebaser
+{
+public:                                
+               MultiArchRebaser::MultiArchRebaser(const char* path, bool writable=false)
+                : fMappingAddress(0), fFileSize(0)
+               {
+                       // map in whole file
+                       int fd = ::open(path, (writable ? O_RDWR : O_RDONLY), 0);
+                       if ( fd == -1 )
+                               throwf("can't open file, errno=%d", errno);
+                       struct stat stat_buf;
+                       if ( fstat(fd, &stat_buf) == -1)
+                               throwf("can't stat open file %s, errno=%d", path, errno);
+                       if ( stat_buf.st_size < 20 )
+                               throwf("file too small %s", path);
+                       const int prot = writable ? (PROT_READ | PROT_WRITE) : PROT_READ;
+                       const int flags = writable ? (MAP_FILE | MAP_SHARED) : (MAP_FILE | MAP_PRIVATE);
+                       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, prot, flags, fd, 0);
+                       if ( p == (uint8_t*)(-1) )
+                               throwf("can't map file %s, errno=%d", path, errno);
+                       ::close(fd);
+
+                       // if fat file, process each architecture
+                       const fat_header* fh = (fat_header*)p;
+                       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);
+                                       try {
+                                               switch ( OSSwapBigToHostInt32(archs[i].cputype) ) {
+                                                       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;
+                                                       default:
+                                                               throw "unknown file format";
+                                               }
+                                       }
+                                       catch (const char* msg) {
+                                               fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+                                       }
+                               }
+                       }
+                       else {
+                               try {
+                                       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 {
+                                               throw "unknown file format";
+                                       }
+                               }
+                               catch (const char* msg) {
+                                       fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+                               }
+                       }
+                       
+                       fMappingAddress = p;
+                       fFileSize = stat_buf.st_size;
+               }
+
+
+               ~MultiArchRebaser()     {::munmap(fMappingAddress, fFileSize); }
+
+       const std::vector<AbstractRebaser*>&            getArchs() const { return fRebasers; }
+       void                                                                            commit()                { ::msync(fMappingAddress, fFileSize, MS_ASYNC);  }
+
+private:
+       std::vector<AbstractRebaser*>                           fRebasers;
+       void*                                                                           fMappingAddress;
+       uint64_t                                                                        fFileSize;
+};
+#endif
+
+
+#endif // __MACHO_REBASER__
+
+
+
+
diff --git a/launch-cache/com.apple.dyld.plist b/launch-cache/com.apple.dyld.plist
new file mode 100644 (file)
index 0000000..7481c33
--- /dev/null
@@ -0,0 +1,26 @@
+<?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>
+       <key>ThrottleInterval</key>
+       <integer>60</integer>
+</dict>
+</plist>
diff --git a/launch-cache/dyld_cache_format.h b/launch-cache/dyld_cache_format.h
new file mode 100644 (file)
index 0000000..c13ff7f
--- /dev/null
@@ -0,0 +1,58 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006-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@
+ */
+#ifndef __DYLD_CACHE_FORMAT__
+#define __DYLD_CACHE_FORMAT__
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <mach/shared_memory_server.h>
+
+
+ struct dyld_cache_header
+{
+       char            magic[16];                              // e.g. "dyld_v0     ppc"
+       uint32_t        mappingOffset;                  // file offset to first shared_file_mapping_np
+       uint32_t        mappingCount;                   // number of shared_file_mapping_np entries
+       uint32_t        imagesOffset;                   // file offset to first dyld_cache_image_info
+       uint32_t        imagesCount;                    // number of dyld_cache_image_info entries
+       uint64_t        dyldBaseAddress;                // base address of dyld when cache was built
+};
+
+struct dyld_cache_image_info
+{
+       uint64_t        address;
+       uint64_t        modTime;
+       uint64_t        inode;
+       uint32_t        pathFileOffset;
+       uint32_t        pad;
+};
+
+#define DYLD_SHARED_CACHE_DIR                  "/var/db/dyld/"
+#define DYLD_SHARED_CACHE_BASE_NAME            "dyld_shared_cache_"
+
+
+
+#endif // __DYLD_CACHE_FORMAT__
+
+
diff --git a/launch-cache/dyld_shared_cache.defs b/launch-cache/dyld_shared_cache.defs
new file mode 100644 (file)
index 0000000..4914364
--- /dev/null
@@ -0,0 +1,19 @@
+#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);
+
diff --git a/launch-cache/update_dyld_shared_cache.cpp b/launch-cache/update_dyld_shared_cache.cpp
new file mode 100644 (file)
index 0000000..4ec8cf8
--- /dev/null
@@ -0,0 +1,1845 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006-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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <dirent.h>
+#include <servers/bootstrap.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+
+#include "dyld_cache_format.h"
+
+#include <vector>
+#include <set>
+#include <map>
+#include <ext/hash_map>
+
+#include "Architectures.hpp"
+#include "MachOLayout.hpp"
+#include "MachORebaser.hpp"
+#include "MachOBinder.hpp"
+#include "CacheFileAbstraction.hpp"
+
+extern "C" { 
+       #include "dyld_shared_cache_server.h"
+}
+
+
+static bool                                                    verbose = false;
+static std::vector<const char*>                warnings;
+
+
+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);
+       
+       cpu_type_t                                                                                      getArch() { return fArch; }
+       std::set<const class MachOLayoutAbstraction*>&          getSharedDylibs() { return fSharedDylibs; }
+       
+private:
+       
+       class DependencyNode
+       {
+       public:
+                                                                               DependencyNode(ArchGraph*, const char* path, const MachOLayoutAbstraction* layout);
+               void                                                    loadDependencies(const MachOLayoutAbstraction*);
+               void                                                    markNeededByRoot(DependencyNode*);
+               const char*                                             getPath() const { return fPath; }
+               const MachOLayoutAbstraction*   getLayout() const { return fLayout; }
+               size_t                                                  useCount() const { return fRootsDependentOnThis.size(); }
+               bool                                                    allDependentsFound() const { return !fDependentMissing; }
+       private:
+               ArchGraph*                                                                      fGraph;
+               const char*                                                                     fPath;
+               const MachOLayoutAbstraction*                           fLayout;
+               bool                                                                            fDependenciesLoaded;
+               bool                                                                            fDependentMissing;
+               std::set<DependencyNode*>                                       fDependsOn;
+               std::set<DependencyNode*>                                       fRootsDependentOnThis;
+       };
+
+       struct CStringEquals {
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
+
+
+                                                               ArchGraph(cpu_type_t arch) : fArch(arch) {}
+       static void                                     addRootForArch(const char* path, const MachOLayoutAbstraction*);
+       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 std::map<cpu_type_t, ArchGraph*> fgPerArchGraph;
+       static const char*                                              fgFileSystemRoot;
+       
+       cpu_type_t                                                                      fArch;
+       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;
+const char*                                                    ArchGraph::fgFileSystemRoot = "";
+
+void ArchGraph::addArch(cpu_type_t arch)
+{
+       //fprintf(stderr, "adding arch 0x%08X\n", arch);
+       fgPerArchGraph[arch] = new ArchGraph(arch);
+}
+
+void ArchGraph::addRoot(const char* vpath, const std::set<cpu_type_t>& archs)
+{
+       char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
+       const char* path;
+       if ( strlen(fgFileSystemRoot) == 0 ) {
+               path = vpath;
+       }
+       else {
+               strcpy(completePath, fgFileSystemRoot);
+               strcat(completePath, vpath);    // assumes vpath starts with '/'
+               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);
+               }
+               // 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)
+{
+       if ( verbose )
+               fprintf(stderr, "update_dyld_shared_cache: adding root: %s\n", path);
+       DependencyNode* node = this->getNode(path);
+       fRoots.insert(node);
+       const MachOLayoutAbstraction* mainExecutableLayout = NULL;
+       if ( layout->getFileType() == MH_EXECUTE )
+               mainExecutableLayout = layout;
+       node->loadDependencies(mainExecutableLayout);
+       node->markNeededByRoot(node);
+       if ( layout->getFileType() == MH_DYLIB )
+               node->markNeededByRoot(NULL);
+}
+
+// a virtual path does not have the fgFileSystemRoot prefix
+ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
+{
+       if ( fgFileSystemRoot == NULL ) {
+               return this->getNode(vpath);
+       }
+       else {
+               char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
+               strcpy(completePath, fgFileSystemRoot);
+               strcat(completePath, vpath);    // assumes vpath starts with '/'
+               return this->getNode(completePath);
+       }
+}
+
+ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
+{
+       // look up supplied path to see if node already exists
+       PathToNode::iterator pos = fNodes.find(path);
+       if ( pos != fNodes.end() )
+               return pos->second;
+       
+       // get real path
+       char realPath[MAXPATHLEN];
+       if ( realpath(path, realPath) == NULL )
+               throwf("realpath() failed on %s\n", path);
+       
+       // look up real path to see if node already exists
+       pos = fNodes.find(realPath);
+       if ( pos != fNodes.end() )
+               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));
+       if ( node->getLayout() == NULL ) {
+               throwf("%s is missing arch %s", realPath, archName(fArch));
+       }
+       // add realpath to node map
+       fNodes[node->getPath()] = node;
+       // if install name is not real path, add install name to node map
+       if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
+               //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
+               fNodes[node->getLayout()->getID().name] = node;
+       }
+       return node;
+}
+       
+       
+void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* mainExecutableLayout)
+{
+       if ( !fDependenciesLoaded ) {
+               fDependenciesLoaded = true;
+               // add dependencies
+               const std::vector<MachOLayoutAbstraction::Library>&     dependsOn = fLayout->getLibraries();
+               for(std::vector<MachOLayoutAbstraction::Library>::const_iterator it = dependsOn.begin(); it != dependsOn.end(); ++it) {
+                       try {
+                               const char* dependentPath = it->name;
+                               if ( strncmp(dependentPath, "@executable_path/", 17) == 0 ) {
+                                       if ( mainExecutableLayout == NULL )
+                                               throw "@executable_path without main executable";
+                                       // expand @executable_path path prefix
+                                       const char* executablePath = mainExecutableLayout->getFilePath();
+                                       char newPath[strlen(executablePath) + strlen(dependentPath)+2];
+                                       strcpy(newPath, executablePath);
+                                       char* addPoint = strrchr(newPath,'/');
+                                       if ( addPoint != NULL )
+                                               strcpy(&addPoint[1], &dependentPath[17]);
+                                       else
+                                               strcpy(newPath, &dependentPath[17]);
+                                       dependentPath = strdup(newPath);
+                               }
+                               else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
+                                       // expand @loader_path path prefix
+                                       char newPath[strlen(fPath) + strlen(dependentPath)+2];
+                                       strcpy(newPath, fPath);
+                                       char* addPoint = strrchr(newPath,'/');
+                                       if ( addPoint != NULL )
+                                               strcpy(&addPoint[1], &dependentPath[13]);
+                                       else
+                                               strcpy(newPath, &dependentPath[13]);
+                                       dependentPath = strdup(newPath);
+                               }
+                               else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
+                                       throw "@rpath not supported in dyld shared cache";
+                               }
+                               fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
+                       }
+                       catch (const char* msg) {
+                               fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
+                               fDependentMissing = true;
+                       }
+               }
+               // recurse
+               for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
+                       (*it)->loadDependencies(mainExecutableLayout);
+               }
+       }
+}
+
+void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode* rootNode)
+{
+       if ( fRootsDependentOnThis.count(rootNode) == 0 ) {
+               fRootsDependentOnThis.insert(rootNode);
+               for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
+                       (*it)->markNeededByRoot(rootNode);
+               }
+       }
+}
+
+
+ArchGraph::DependencyNode::DependencyNode(ArchGraph* graph, const char* path, const MachOLayoutAbstraction* layout) 
+ : fGraph(graph), fPath(strdup(path)), fLayout(layout), fDependenciesLoaded(false), fDependentMissing(false)
+{
+       //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
+}
+
+void ArchGraph::findSharedDylibs(cpu_type_t arch)
+{
+       const PathToNode& nodes = fgPerArchGraph[arch]->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());
+                       //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::map<const MachOLayoutAbstraction*,bool> shareableMap;
+       for (std::set<const MachOLayoutAbstraction*>::iterator lit = possibleLibs.begin(); lit != possibleLibs.end(); ++lit) {
+               if ( canBeShared(*lit, arch, possibleLibs, shareableMap) )
+                       sharedLibs.insert(*lit);
+       }
+}
+
+const char*    ArchGraph::archName(cpu_type_t arch)
+{
+       switch ( 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";
+               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)
+{
+       // check map which is a cache of results
+       std::map<const MachOLayoutAbstraction*, bool>::iterator mapPos = shareableMap.find(layout);
+       if ( mapPos != shareableMap.end() ) {
+               return mapPos->second;
+       }
+       // see if possible
+       if ( possibleLibs.count(layout) == 0 ) {
+               shareableMap[layout] = false;
+               char* msg;
+               if ( ! layout->hasSplitSegInfo() )
+                       asprintf(&msg, "can't put %s in shared cache because it was not built for 10.5", 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);
+               return false;
+       }
+       // look recursively
+       shareableMap[layout] = true; // mark this shareable early in case of circular references
+       const PathToNode& nodes = fgPerArchGraph[arch]->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() ) {
+                       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);
+                       return false;
+               }
+               else {
+                       if ( ! canBeShared(pos->second->getLayout(), arch, 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);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+
+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, int archIndex, int archCount);
+       static const char*              filename(bool optimized);
+
+private:
+       typedef typename A::P::E        E;
+
+       bool                                    notUpToDate(const char* cachePath);
+       bool                                    notUpToDate(const void* cache);
+       uint8_t*                                optimizeLINKEDIT();
+
+       static void                             getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
+       static cpu_type_t               arch();
+       static const char*              archName();
+       static uint64_t                 sharedRegionReadOnlyStartAddress();
+       static uint64_t                 sharedRegionWritableStartAddress();
+       static uint64_t                 sharedRegionReadOnlySize();
+       static uint64_t                 sharedRegionWritableSize();
+       static uint64_t                 getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
+       
+       
+       void                                    assignNewBaseAddresses();
+       uint64_t                                cacheFileOffsetForAddress(uint64_t addr);
+
+       struct LayoutInfo {
+               const MachOLayoutAbstraction*           layout;
+               dyld_cache_image_info                           info;
+       };
+       
+       struct ByNameSorter {
+               bool operator()(const LayoutInfo& left, const LayoutInfo& right) 
+                               { 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();
+               }
+               bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
+                       return (fMap[left.layout] < fMap[right.layout]); 
+               }
+       private:
+               std::map<const MachOLayoutAbstraction*, uint32_t> fMap;
+       };
+       
+
+       ArchGraph*                                                      fArchGraph;
+       std::vector<LayoutInfo>                         fDylibs;
+       std::vector<shared_file_mapping_np>     fMappings;
+       uint32_t                                                        fHeaderSize;
+       uint8_t*                                                        fMappedCacheFile;
+       uint64_t                                                        fDyldBaseAddress;
+       uint64_t                                                        fLinkEditsTotalUnoptimizedSize;
+       uint64_t                                                        fLinkEditsStartAddress;
+       MachOLayoutAbstraction::Segment*        fFirstLinkEditSegment;
+};
+
+
+
+       
+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 <>     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<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<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<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 <>     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<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 <typename A>
+SharedCache<A>::SharedCache(ArchGraph* graph, bool alphaSort, uint64_t dyldBaseAddress) 
+  : fArchGraph(graph), fDyldBaseAddress(dyldBaseAddress)
+{
+       if ( fArchGraph->getArch() != arch() )
+               throw "wrong architecture";
+       
+       // 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) {
+               const MachOLayoutAbstraction* lib = *it;
+               LayoutInfo temp;
+               temp.layout = lib;
+               temp.info.address = 0;
+               temp.info.modTime = lib->getLastModTime();
+               temp.info.inode = lib->getInode();
+               temp.info.pathFileOffset = lib->getNameFileOffset();
+               fDylibs.push_back(temp);
+       }
+       
+       // sort shared dylibs
+       if ( alphaSort )
+               std::sort(fDylibs.begin(), fDylibs.end(), ByNameSorter());
+       else
+               std::sort(fDylibs.begin(), fDylibs.end(), RandomSorter(fDylibs));
+               
+       
+       // assign segments in each dylib a new address
+       this->assignNewBaseAddresses();
+       
+       // calculate cache file header size
+       fHeaderSize = pageAlign(sizeof(dyld_cache_header) 
+                                                       + fMappings.size()*sizeof(shared_file_mapping_np) 
+                                                       + fDylibs.size()*sizeof(dyld_cache_image_info) );
+                                                       //+ fDependencyPool.size()*sizeof(uint16_t));
+       
+       if ( fHeaderSize > 0x3000 )
+               throwf("header size miscalculation 0x%08X", fHeaderSize);
+}
+
+
+template <typename A>
+uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
+{
+       return proposedNewAddress;
+}
+
+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)
+       return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
+}
+
+
+template <typename A>
+void SharedCache<A>::assignNewBaseAddresses()
+{
+       // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
+       uint64_t currentExecuteAddress = sharedRegionReadOnlyStartAddress() + 0x3000;   
+       uint64_t currentWritableAddress = sharedRegionWritableStartAddress();
+       for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+               MachOLayoutAbstraction::Segment* executableSegment = NULL;
+               for (int i=0; i < segs.size(); ++i) {
+                       MachOLayoutAbstraction::Segment& seg = segs[i];
+                       if ( seg.writable() ) {
+                               if ( seg.executable() && it->layout->hasSplitSegInfo() ) {
+                                       // skip __IMPORT segments in this pass
+                               }
+                               else {
+                                       // __DATA segment
+                                       // for ppc, writable segments have to move in 64K increments
+                                       if (  it->layout->hasSplitSegInfo() ) {
+                                               if ( executableSegment == NULL )
+                                                       throwf("first segment in dylib is not executable for %s", it->layout->getID().name);
+                                               seg.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress, seg.address(), executableSegment->newAddress() - executableSegment->address()));
+                                       }
+                                       else
+                                               seg.setNewAddress(currentWritableAddress);
+                                       currentWritableAddress = pageAlign(seg.newAddress() + seg.size());
+                               }
+                       }
+                       else {
+                               if ( seg.executable() ) {
+                                       // __TEXT segment
+                                       if ( it->info.address == 0 )
+                                               it->info.address = currentExecuteAddress;
+                                       executableSegment = &seg;
+                                       seg.setNewAddress(currentExecuteAddress);
+                                       currentExecuteAddress += pageAlign(seg.size());
+                               }
+                               else {
+                                       // skip read-only segments in this pass
+                                       // 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());
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
+       // append all IMPORT segments at end of all DATA segments rounded to next 2MB 
+       uint64_t currentReadOnlyAddress = currentExecuteAddress;
+       uint64_t startWritableExecutableAddress = (currentWritableAddress + 0x200000 - 1) & (-0x200000);
+       uint64_t currentWritableExecutableAddress = startWritableExecutableAddress;
+       for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+               for(int i=0; i < segs.size(); ++i) {
+                       MachOLayoutAbstraction::Segment& seg = segs[i];
+                       if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
+                               // allocate non-executable,read-only segments from end of read only shared region
+                               seg.setNewAddress(currentReadOnlyAddress);
+                               currentReadOnlyAddress += pageAlign(seg.size());
+                       }
+                       else if ( seg.writable() && seg.executable() && it->layout->hasSplitSegInfo() ) {
+                               // allocate IMPORT segments to end of writable shared region
+                               seg.setNewAddress(currentWritableExecutableAddress);
+                               seg.setWritable(false); // __IMPORT segments are not-writable in shared cache
+                               currentWritableExecutableAddress += pageAlign(seg.size());
+                       }
+               }
+       }       
+
+       // append all LINKEDIT segments at end of all read-only segments
+       fLinkEditsStartAddress = currentReadOnlyAddress;
+       fFirstLinkEditSegment = NULL;
+       for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+               for(int i=0; i < segs.size(); ++i) {
+                       MachOLayoutAbstraction::Segment& seg = segs[i];
+                       if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
+                               if ( fFirstLinkEditSegment == NULL ) 
+                                       fFirstLinkEditSegment = &seg;
+                               // allocate non-executable,read-only segments from end of read only shared region
+                               seg.setNewAddress(currentReadOnlyAddress);
+                               currentReadOnlyAddress += pageAlign(seg.size());
+                       }
+               }
+       }
+       fLinkEditsTotalUnoptimizedSize = (currentReadOnlyAddress - fLinkEditsStartAddress + 4095) & (-4096);
+
+
+       // populate large mappings
+       uint64_t cacheFileOffset = 0;
+       if ( currentExecuteAddress > sharedRegionReadOnlyStartAddress() + 0x3000 ) {
+               shared_file_mapping_np  executeMapping;
+               executeMapping.sfm_address              = sharedRegionReadOnlyStartAddress();
+               executeMapping.sfm_size                 = currentExecuteAddress - sharedRegionReadOnlyStartAddress();
+               executeMapping.sfm_file_offset  = cacheFileOffset;
+               executeMapping.sfm_max_prot             = VM_PROT_READ | VM_PROT_EXECUTE;
+               executeMapping.sfm_init_prot    = VM_PROT_READ | VM_PROT_EXECUTE;
+               fMappings.push_back(executeMapping);
+               cacheFileOffset += executeMapping.sfm_size;
+               
+               shared_file_mapping_np  writableMapping;
+               writableMapping.sfm_address             = sharedRegionWritableStartAddress();
+               writableMapping.sfm_size                = currentWritableAddress - sharedRegionWritableStartAddress();
+               writableMapping.sfm_file_offset = cacheFileOffset;
+               writableMapping.sfm_max_prot    = VM_PROT_READ | VM_PROT_WRITE;
+               writableMapping.sfm_init_prot   = VM_PROT_READ | VM_PROT_WRITE;
+               fMappings.push_back(writableMapping);
+               cacheFileOffset += writableMapping.sfm_size;
+               
+               if ( currentWritableExecutableAddress > startWritableExecutableAddress ) {
+                       shared_file_mapping_np  writableExecutableMapping;
+                       writableExecutableMapping.sfm_address   = startWritableExecutableAddress;
+                       writableExecutableMapping.sfm_size              = currentWritableExecutableAddress - startWritableExecutableAddress;
+                       writableExecutableMapping.sfm_file_offset= cacheFileOffset;
+                       writableExecutableMapping.sfm_max_prot  = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+                       // __IMPORT segments in shared cache are not writable 
+                       writableExecutableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_EXECUTE; 
+                       fMappings.push_back(writableExecutableMapping);
+                       cacheFileOffset += writableExecutableMapping.sfm_size;
+               }
+               
+               // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
+               shared_file_mapping_np  readOnlyMapping;
+               readOnlyMapping.sfm_address             = currentExecuteAddress;
+               readOnlyMapping.sfm_size                = currentReadOnlyAddress - currentExecuteAddress;
+               readOnlyMapping.sfm_file_offset = cacheFileOffset;
+               readOnlyMapping.sfm_max_prot    = VM_PROT_READ;
+               readOnlyMapping.sfm_init_prot   = VM_PROT_READ;
+               fMappings.push_back(readOnlyMapping);
+               cacheFileOffset += readOnlyMapping.sfm_size;
+       }
+       else {
+               // empty cache
+               shared_file_mapping_np  cacheHeaderMapping;
+               cacheHeaderMapping.sfm_address          = sharedRegionWritableStartAddress();
+               cacheHeaderMapping.sfm_size                     = 0x3000;
+               cacheHeaderMapping.sfm_file_offset      = cacheFileOffset;
+               cacheHeaderMapping.sfm_max_prot         = VM_PROT_READ;
+               cacheHeaderMapping.sfm_init_prot        = VM_PROT_READ;
+               fMappings.push_back(cacheHeaderMapping);
+               cacheFileOffset += cacheHeaderMapping.sfm_size;
+       }
+}
+
+
+template <typename A>
+uint64_t SharedCache<A>::cacheFileOffsetForAddress(uint64_t addr)
+{
+       for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+               if ( (it->sfm_address <= addr) && (addr < it->sfm_address+it->sfm_size) )
+                       return it->sfm_file_offset + addr - it->sfm_address;
+       }
+       throwf("address 0x%0llX is not in cache", addr);
+}
+
+
+template <typename A>
+bool SharedCache<A>::notUpToDate(const void* cache)
+{
+       dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
+       // not valid if header signature is wrong
+       char temp[16];
+       strcpy(temp, "dyld_v1        ");
+       strcpy(&temp[15-strlen(archName())], archName());
+       if ( strcmp(header->magic(), temp) != 0 ) 
+               return true;
+       // not valid if count of images does not match current images needed
+       if ( header->imagesCount() != fDylibs.size() )
+               return true;
+       // verify every dylib in constructed graph is in existing cache with same inode and modTime     
+       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) ) {
+                                       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;
+               }
+       }
+       return false;
+}
+
+
+template <typename A>
+bool SharedCache<A>::notUpToDate(const char* cachePath)
+{
+       // mmap existing cache file 
+       int fd = ::open(cachePath, O_RDONLY);   
+       if ( fd == -1 )
+               return true;
+       struct stat stat_buf;
+       ::fstat(fd, &stat_buf);
+       uint8_t* mappingAddr = (uint8_t*)mmap(NULL, stat_buf.st_size, PROT_READ , MAP_FILE | MAP_PRIVATE, fd, 0);
+       ::close(fd);
+       if ( mappingAddr == (uint8_t*)(-1) )
+               return true;
+
+       // 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);
+
+       return result;
+}
+
+class CStringEquals
+{
+public:
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+class StringPool
+{
+public:
+                               StringPool();
+       const char*     getBuffer();
+       uint32_t        size();
+       uint32_t        add(const char* str);
+       uint32_t        addUnique(const char* str);
+       const char* stringAtIndex(uint32_t) const;
+private:
+       typedef __gnu_cxx::hash_map<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+
+       char*                   fBuffer;
+       uint32_t                fBufferAllocated;
+       uint32_t                fBufferUsed;
+       StringToOffset  fUniqueStrings;
+};
+
+
+StringPool::StringPool() 
+       : fBufferUsed(0), fBufferAllocated(4*1024*1024)
+{
+       fBuffer = (char*)malloc(fBufferAllocated);
+}
+
+uint32_t StringPool::add(const char* str)
+{
+       uint32_t len = strlen(str);
+       if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
+               // grow buffer
+               fBufferAllocated = fBufferAllocated*2;
+               fBuffer = (char*)realloc(fBuffer, fBufferAllocated);
+       }
+       strcpy(&fBuffer[fBufferUsed], str);
+       uint32_t result = fBufferUsed;
+       fUniqueStrings[&fBuffer[fBufferUsed]] = result;
+       fBufferUsed += len+1;
+       return result;
+}
+
+uint32_t StringPool::addUnique(const char* str)
+{
+       StringToOffset::iterator pos = fUniqueStrings.find(str);
+       if ( pos != fUniqueStrings.end() ) 
+               return pos->second;
+       else {
+               //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
+               return this->add(str);
+       }
+}
+
+uint32_t StringPool::size()
+{
+       return fBufferUsed;
+}
+
+const char*    StringPool::getBuffer()
+{
+       return fBuffer;
+}
+
+const char* StringPool::stringAtIndex(uint32_t index) const
+{
+       return &fBuffer[index];
+}
+
+
+template <typename A>
+class LinkEditOptimizer
+{
+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);
+       
+
+protected:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+                       
+private:
+
+       const macho_header<P>*                                          fHeader; 
+       uint8_t*                                                                        fNewLinkEditStart;      
+       uint8_t*                                                                        fLinkEditBase;          
+       const MachOLayoutAbstraction&                           fLayout;
+       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                                                                        fLocalSymbolsStartIndexInNewLinkEdit;
+       uint32_t                                                                        fLocalSymbolsCountInNewLinkEdit;
+       uint32_t                                                                        fExportedSymbolsStartIndexInNewLinkEdit;
+       uint32_t                                                                        fExportedSymbolsCountInNewLinkEdit;
+       uint32_t                                                                        fImportSymbolsStartIndexInNewLinkEdit;
+       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), 
+       fDynamicSymbolTable(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
+       fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
+       fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
+       fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
+       fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
+       
+{
+       fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
+
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
+               const MachOLayoutAbstraction::Segment& seg = *it;
+               if ( strcmp(seg.name(), "__LINKEDIT") == 0 ) 
+                       fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
+       }
+       if ( fLinkEditBase == NULL )    
+               throw "no __LINKEDIT segment";
+
+       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:
+                               {
+                                       fSymbolTableLoadCommand = (macho_symtab_command<P>*)cmd;
+                                       fSymbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTableLoadCommand->symoff()]);
+                                       fStrings = (char*)&fLinkEditBase[fSymbolTableLoadCommand->stroff()];
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+       if ( fSymbolTable == NULL )     
+               throw "no LC_SYMTAB";
+       if ( fDynamicSymbolTable == NULL )      
+               throw "no LC_DYSYMTAB";
+       
+}
+
+
+template <typename A>
+class SymbolSorter
+{
+public:
+       typedef typename A::P P;
+       SymbolSorter(const StringPool& pool) : fStringPool(pool) {}
+       bool operator()(const macho_nlist<P>& left, const macho_nlist<P>& right) { 
+               return (strcmp(fStringPool.stringAtIndex(left.n_strx()) , fStringPool.stringAtIndex(right.n_strx())) < 0); 
+       } 
+       
+private:
+       const StringPool& fStringPool;
+};
+
+
+template <typename A>
+void LinkEditOptimizer<A>::makeDummyLocalSymbol(uint32_t& symbolIndex, uint8_t* storage, StringPool& pool)
+{
+       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;
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::copyLocalSymbols()
+{
+       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;
+       }
+}
+
+
+template <typename A>
+void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t& symbolIndex)
+{
+       fExportedSymbolsStartIndexInNewLinkEdit = symbolIndex;
+       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];
+                       *newSymbolEntry = *entry;
+                       newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
+                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex;
+                       ++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];
+       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()));
+}
+
+
+template <typename A>
+void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t& symbolIndex)
+{
+       fImportSymbolsStartIndexInNewLinkEdit = symbolIndex;
+       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];
+                       *newSymbolEntry = *entry;
+                       newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
+                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex;
+                       ++symbolIndex;
+               }
+       }
+       fImportedSymbolsCountInNewLinkEdit = symbolIndex - fImportSymbolsStartIndexInNewLinkEdit;
+       //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
+       //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
+       //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
+       //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
+       //      fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
+}
+
+
+template <typename A>
+void LinkEditOptimizer<A>::copyExternalRelocations(uint32_t& offset)
+{
+       fExternalRelocationsOffsetIntoNewLinkEdit = offset;
+       const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
+       const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
+       for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               macho_relocation_info<P>* newReloc = (macho_relocation_info<P>*)(&fNewLinkEditStart[offset]);
+               *newReloc = *reloc;
+               uint32_t newSymbolIndex = fOldToNewSymbolIndexes[reloc->r_symbolnum()];
+               //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
+               //       &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
+               newReloc->set_r_symbolnum(newSymbolIndex);
+               offset += sizeof(macho_relocation_info<P>);
+       }
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
+{      
+       fIndirectSymbolTableOffsetInfoNewLinkEdit = offset;
+       const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicSymbolTable->indirectsymoff()];
+       uint32_t* newIndirectTable = (uint32_t*)&fNewLinkEditStart[offset];
+       for (int i=0; i < fDynamicSymbolTable->nindirectsyms(); ++i) {
+               uint32_t oldSymbolIndex = E::get32(indirectTable[i]); 
+               uint32_t newSymbolIndex = oldSymbolIndex;
+               if ( (oldSymbolIndex != INDIRECT_SYMBOL_ABS) && (oldSymbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
+                       newSymbolIndex = fOldToNewSymbolIndexes[oldSymbolIndex];
+                       //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
+                       // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
+               }
+               E::set32(newIndirectTable[i], newSymbolIndex);
+       }
+       offset += (fDynamicSymbolTable->nindirectsyms() * 4);
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset)
+{
+       // 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;
+                       if ( strcmp(seg->segname(), "__LINKEDIT") == 0 ) {
+                               seg->set_vmaddr(newVMAddress);
+                               seg->set_vmsize(size);
+                               seg->set_filesize(size);
+                               linkEditStartFileOffset = seg->fileoff();
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+               
+       // 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_strsize(fNewStringPool.size());
+       fDynamicSymbolTable->set_ilocalsym(fLocalSymbolsStartIndexInNewLinkEdit);
+       fDynamicSymbolTable->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit);
+       fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit);
+       fDynamicSymbolTable->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit);
+       fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit);
+       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_locreloff(0);
+       fDynamicSymbolTable->set_nlocrel(0);
+}
+
+
+
+template <typename A>
+uint8_t* SharedCache<A>::optimizeLINKEDIT()
+{
+       // allocate space for optimized LINKEDIT area
+       uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
+       bzero(newLinkEdit, fLinkEditsTotalUnoptimizedSize);
+       
+       // make a string pool 
+       StringPool stringPool;
+       
+       // create optimizer object for each LINKEDIT segment
+       std::vector<LinkEditOptimizer<A>*> optimizers;
+       for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, newLinkEdit, stringPool));
+       }
+
+       // copy local symbol table entries
+       uint32_t symbolTableIndex = 0;
+       LinkEditOptimizer<A>::makeDummyLocalSymbol(symbolTableIndex, newLinkEdit, stringPool);
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyLocalSymbols();
+       }
+
+       // copy exported symbol table entries
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyExportedSymbols(symbolTableIndex);
+       }
+       //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
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyImportedSymbols(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 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;
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyIndirectSymbolTable(indirectSymbolTableOffset);
+       }
+       
+       // copy string pool
+       uint32_t stringPoolOffset = indirectSymbolTableOffset;
+       memcpy(&newLinkEdit[stringPoolOffset], stringPool.getBuffer(), stringPool.size());
+       
+       // find new size
+       uint32_t linkEditsTotalOptimizedSize = (stringPoolOffset + stringPool.size() + 4095) & (-4096);
+       
+       // 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);
+       }
+
+       //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, linkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, linkEditsTotalOptimizedSize);
+       //fprintf(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);
+       
+       // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
+       for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+               for(int i=0; i < segs.size(); ++i) {
+                       MachOLayoutAbstraction::Segment& seg = segs[i];
+                       if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
+                               seg.setNewAddress(fLinkEditsStartAddress);
+                               seg.setMappedAddress(fFirstLinkEditSegment->mappedAddress());
+                               seg.setSize(linkEditsTotalOptimizedSize);
+                               seg.setFileSize(linkEditsTotalOptimizedSize);
+                               //seg.setFileOffset(0);
+                       }
+               }
+       }
+       
+       // return new end of cache
+       return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + linkEditsTotalOptimizedSize;
+}
+
+
+template <typename A>
+bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool force, bool optimize, int archIndex, int archCount)
+{
+       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 ( verbose )
+                       fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", cachePath);
+               if ( fDylibs.size() == 0 ) {
+                       fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
+                       return false;
+               }
+               char tempCachePath[strlen(cachePath)+16];
+               sprintf(tempCachePath, "%s.tmp%u", cachePath, getpid());
+               try {
+                       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
+                       uint32_t cacheFileSize = 0;
+                       for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+                               uint32_t end = it->sfm_file_offset + it->sfm_size;
+                               if ( end > cacheFileSize )
+                                       cacheFileSize = end;
+                       }
+                       fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
+                       fcntl(fd, F_PREALLOCATE, &fcntlSpec);
+  
+                       // fill in cache header memory buffer
+                       uint8_t buffer[pageAlign(fHeaderSize)];
+                       bzero(buffer, sizeof(buffer));
+                       
+                       // fill in header
+                       dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)buffer;
+                       char temp[16];
+                       strcpy(temp, "dyld_v1        ");
+                       strcpy(&temp[15-strlen(archName())], archName());
+                       header->set_magic(temp);
+                       //header->set_architecture(arch());
+                       header->set_mappingOffset(sizeof(dyldCacheHeader<E>)); 
+                       header->set_mappingCount(fMappings.size());
+                       header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));   
+                       header->set_imagesCount(fDylibs.size());
+                       header->set_dyldBaseAddress(fDyldBaseAddress);
+                       //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>)); 
+                       //header->set_dependenciesCount(fDependencyPool.size());
+                       
+                       // fill in mappings
+                       dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&buffer[sizeof(dyldCacheHeader<E>)];
+                       for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+                               if ( verbose )
+                                       fprintf(stderr, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n", 
+                                                                       it->sfm_address, it->sfm_size, it->sfm_file_offset, it->sfm_init_prot);
+                               mapping->set_address(it->sfm_address);
+                               mapping->set_size(it->sfm_size);
+                               mapping->set_file_offset(it->sfm_file_offset);
+                               mapping->set_max_prot(it->sfm_max_prot);
+                               mapping->set_init_prot(it->sfm_init_prot);
+                               ++mapping;
+                       }
+                       
+                       // fill in image table
+                       dyldCacheImageInfo<E>* image = (dyldCacheImageInfo<E>*)mapping;
+                       for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+                               image->set_address(it->info.address);
+                               image->set_modTime(it->info.modTime);
+                               image->set_inode(it->info.inode);
+                               image->set_pathFileOffset(cacheFileOffsetForAddress(it->info.address+it->info.pathFileOffset));
+                               //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
+                               ++image;
+                       }
+                                               
+                       // write whole header to disk
+                       pwrite(fd, buffer, sizeof(buffer), 0);
+                       
+                       // allocate copy buffer
+                       const uint64_t kCopyBufferSize = 256*1024;
+                       uint8_t* copyBuffer;
+                       vm_address_t addr = 0;
+                       if ( vm_allocate(mach_task_self(), &addr, kCopyBufferSize, VM_FLAGS_ANYWHERE) == KERN_SUCCESS )
+                               copyBuffer = (uint8_t*)addr;
+                       else
+                               throw "can't allcoate copy buffer";
+
+                       // make zero-fill buffer
+                       uint8_t zerofill[4096];
+                       bzero(zerofill, sizeof(zerofill));
+
+                       // write each segment to cache file
+                       int dylibIndex = 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);    
+                               if ( src == -1 )
+                                       throwf("can't open file %s, errnor=%d", it->layout->getID().name, errno);
+                               // mark source as "don't cache"
+                               (void)fcntl(src, F_NOCACHE, 1);
+
+                               if ( verbose )
+                                       fprintf(stderr, "update_prebinding: copying %s to cache\n", it->layout->getID().name);
+                               try {
+                                       const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
+                                       for (int i=0; i < segs.size(); ++i) {
+                                               const MachOLayoutAbstraction::Segment& seg = segs[i];
+                                               if ( verbose )
+                                                       fprintf(stderr, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg.name(), seg.fileSize(), seg.newAddress());
+                                               if ( seg.size() > 0 ) {
+                                                       const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
+                                                       const uint64_t segmentSize = seg.fileSize();
+                                                       const uint64_t segmentDstStartOffset = cacheFileOffsetForAddress(seg.newAddress());
+                                                       for(uint64_t copiedAmount=0; copiedAmount < segmentSize; copiedAmount += kCopyBufferSize) {
+                                                               uint64_t amount = std::min(segmentSize-copiedAmount, kCopyBufferSize);
+                                                               //fprintf(stderr, "copy 0x%08llX bytes at offset 0x%08llX for segment %s in %s to cache offset 0x%08llX\n", 
+                                                               //              amount, segmentSrcStartOffset+copiedAmount, seg.name(), it->layout->getID().name, segmentDstStartOffset+copiedAmount);
+                                                               if ( ::pread(src, copyBuffer, amount, segmentSrcStartOffset+copiedAmount) != amount )
+                                                                       throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
+                                                               if ( ::pwrite(fd, copyBuffer, amount, segmentDstStartOffset+copiedAmount) != amount )
+                                                                       throwf("write failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
+                                                       }
+                                                       if ( seg.size() > seg.fileSize() ) {
+                                                               // write zero-filled area
+                                                               for(uint64_t copiedAmount=seg.fileSize(); copiedAmount < seg.size(); copiedAmount += sizeof(zerofill)) {
+                                                                       uint64_t amount = std::min(seg.size()-copiedAmount, (uint64_t)(sizeof(zerofill)));
+                                                                       if ( ::pwrite(fd, zerofill, amount, segmentDstStartOffset+copiedAmount) != amount )
+                                                                               throwf("write failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               catch (const char* msg) {
+                                       throwf("%s while copying %s to shared cache", msg, it->layout->getID().name);
+                               }
+                               ::close(src);
+                       }
+                       
+                       // free copy buffer
+                       vm_deallocate(mach_task_self(), addr, kCopyBufferSize);
+                       
+                       // map cache file
+                       fMappedCacheFile = (uint8_t*)mmap(NULL, cacheFileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+                       if ( fMappedCacheFile == (uint8_t*)(-1) )
+                               throw "can't mmap cache file";
+
+                       // close cache file
+                       ::fsync(fd);
+                       ::close(fd);
+
+                       // set mapped address for each segment
+                       for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+                               std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+                               for (int i=0; i < segs.size(); ++i) {
+                                       MachOLayoutAbstraction::Segment& seg = segs[i];
+                                       if ( seg.size() > 0 )
+                                               seg.setMappedAddress(fMappedCacheFile + cacheFileOffsetForAddress(seg.newAddress()));
+                                       //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
+                               }
+                       }
+
+                       // rebase each dylib in shared cache
+                       for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+                               try {
+                                       Rebaser<A> r(*it->layout);
+                                       r.rebase();
+                                       //if ( verbose )
+                                       //      fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
+                               }
+                               catch (const char* msg) {
+                                       throwf("%s in %s", msg, it->layout->getID().name);
+                               }
+                       }
+                       
+                       // 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() - fMappedCacheFile);
+                               //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>*)fMappedCacheFile;
+                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&fMappedCacheFile[sizeof(dyldCacheHeader<E>)];
+                               dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
+                               lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
+                               // update fMappings so .map file will print correctly
+                               fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
+                       }
+                       
+                       if ( verbose )
+                               fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
+                       // instantiate a Binder for each image and add to map
+                       typename Binder<A>::Map map;
+                       std::vector<Binder<A>*> binders;
+                       for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+                               //fprintf(stderr, "binding %s\n", it->layout->getID().name);
+                               Binder<A>* binder = new Binder<A>(*it->layout, fDyldBaseAddress);
+                               binders.push_back(binder);
+                               // only add dylibs to map
+                               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);
+                       }
+                       // perform binding
+                       for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
+                               if ( verbose )
+                                       fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
+                               try {
+                                       (*it)->bind();
+                               }
+                               catch (const char* msg) {
+                                       throwf("%s in %s", msg, (*it)->getDylibID());
+                               }
+                       }
+                       // delete binders
+                       for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
+                               delete *it;
+                       }
+               
+                       // close mapping
+                       int result = ::msync(fMappedCacheFile, cacheFileSize, MS_SYNC);
+                       if ( result != 0 )
+                               throw "error syncing cache file";
+                       result = ::munmap(fMappedCacheFile, cacheFileSize);
+                       if ( result != 0 )
+                               throw "error unmapping cache file";
+                       
+                       // cut back cache file to match optmized size
+                       if ( optimize ) {
+                               if ( ::truncate(tempCachePath, cacheFileSize) != 0 )
+                                       throw "error truncating cache file";
+                       }
+                       
+                       // commit 
+                       ::sync();
+                       // flush everything to disk, otherwise if kernel panics before the cache file is completely written to disk
+                       // then next reboot will use a corrupted cache and die
+                       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);
+                       // flush everything to disk to assure rename() gets recorded
+                       ::sync();
+                       didUpdate = true;
+
+                       // generate human readable "map" file that shows the layout of the cache file
+                       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);
+                       }
+                       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());
+                                       }
+                               }
+                               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);
+                       }
+               }
+               catch (...){
+                       // remove temp cache
+                       ::unlink(tempCachePath);
+                       throw;
+               }
+       }
+       return didUpdate;
+}
+
+
+
+//
+//     The shared cache is driven by /var/db/dyld/shared_region_roots which contains
+//     the paths used to search for dylibs that should go in the shared cache  
+//
+//     Leading and trailing white space is ignored
+//     Blank lines are ignored
+//     Lines starting with # are ignored
+//
+static void parsePathsFile(const char* filePath, std::vector<const char*>& paths)
+{
+       // read in whole file
+       int fd = open(filePath, O_RDONLY, 0);
+       if ( fd == -1 ) {
+               fprintf(stderr, "update_dyld_shared_cache: can't open file: %s\n", filePath);
+               exit(1);
+       }
+       struct stat stat_buf;
+       fstat(fd, &stat_buf);
+       char* p = (char*)malloc(stat_buf.st_size);
+       if ( p == NULL ) {
+               fprintf(stderr, "update_dyld_shared_cache: malloc failure\n");
+               exit(1);
+       }       
+       if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) {
+               fprintf(stderr, "update_dyld_shared_cache: can't read file: %s\n", filePath);
+               exit(1);
+       }       
+       ::close(fd);
+       
+       // parse into paths and add to vector
+       char * const end = &p[stat_buf.st_size];
+       enum { lineStart, inSymbol, inComment } state = lineStart;
+       char* symbolStart = NULL;
+       for (char* s = p; s < end; ++s ) {
+               switch ( state ) {
+                       case lineStart:
+                               if ( *s =='#' ) {
+                                       state = inComment;
+                               }
+                               else if ( !isspace(*s) ) {
+                                       state = inSymbol;
+                                       symbolStart = s;
+                               }
+                               break;
+                       case inSymbol:
+                               if ( *s == '\n' ) {
+                                       *s = '\0';
+                                       // removing any trailing spaces
+                                       char* last = s-1;
+                                       while ( isspace(*last) ) {
+                                               *last = '\0';
+                                               --last;
+                                       }
+                                       paths.push_back(symbolStart);
+                                       symbolStart = NULL;
+                                       state = lineStart;
+                               }
+                               break;
+                       case inComment:
+                               if ( *s == '\n' )
+                                       state = lineStart;
+                               break;
+               }
+       }
+       // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
+}
+
+
+static void scanForSharedDylibs(const char* rootPath, const char* dirOfPathFiles, const std::set<cpu_type_t>& onlyArchs)
+{
+       char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
+       if ( strlen(rootPath) != 0 ) {
+               strcpy(rootDirOfPathFiles, rootPath);
+               strcat(rootDirOfPathFiles, dirOfPathFiles);
+               dirOfPathFiles = rootDirOfPathFiles;
+       }
+
+       // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
+       if ( verbose )
+               fprintf(stderr, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles);
+       std::vector<const char*> rootsPaths;
+       DIR* dir = ::opendir(dirOfPathFiles);
+       if ( dir == NULL )
+               throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
+       for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
+               if ( entry->d_type == DT_REG ) {
+                       // only look at files ending in .paths
+                       if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
+                               char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
+                               strcpy(fullPath, dirOfPathFiles);
+                               strcat(fullPath, "/");
+                               strcat(fullPath, entry->d_name);
+                               parsePathsFile(fullPath, rootsPaths);
+                       }
+                       else {
+                               fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
+                       }
+               }
+       }
+       ::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");
+}
+
+
+
+static bool updateSharedeCacheFile(const char* rootPath, const char* cacheDir, const std::set<cpu_type_t>& onlyArchs, 
+                                                                       bool force, bool alphaSort, bool optimize)
+{
+       bool didUpdate = false;
+       // get dyld load address info
+       UniversalMachOLayout* 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 ) {
+                       case CPU_TYPE_POWERPC:
+                               {
+                                       SharedCache<ppc> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
+               #if __i386__
+                                       // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
+                                       didUpdate |= cache.update(rootPath, cacheDir, force, false, index, archCount);
+               #else
+                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+               #endif
+                               }
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               {
+                                       SharedCache<ppc64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
+                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+                               }
+                               break;
+                       case CPU_TYPE_I386:
+                               {
+                                       SharedCache<x86> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
+                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+                               }
+                               break;
+                       case CPU_TYPE_X86_64:
+                               {
+                                       SharedCache<x86_64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
+                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, index, archCount);
+                               }
+                               break;
+               }
+       }
+       return didUpdate;
+}
+
+
+static void usage()
+{
+       fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
+}
+
+
+kern_return_t do_dyld_shared_cache_missing(mach_port_t dyld_port, cpu_type_t arch)
+{
+       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) )
+                       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;
+       }
+       return KERN_SUCCESS;
+}
+
+
+kern_return_t do_dyld_shared_cache_out_of_date(mach_port_t dyld_port, cpu_type_t arch)
+{
+       // reduce priority of this process so it only runs at the lowest priority 
+       setpriority(PRIO_PROCESS, 0, PRIO_MAX);
+       
+       // and then rebuild cache
+       return do_dyld_shared_cache_missing(dyld_port, arch);
+}
+
+
+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
+               // Just process one message and quit
+               mach_msg_size_t mxmsgsz = sizeof(union __RequestUnion__do_dyld_server_subsystem) + MAX_TRAILER_SIZE;
+               mach_msg_server_once(dyld_server_server, mxmsgsz, mp, MACH_RCV_TIMEOUT);
+               // The problem with staying alive and processing messages is that the rest of this 
+               // tool leaks mapped memory and file descriptors.  Quiting will clean that up.
+               // <rdar://problem/5392427> 9A516 - Keep getting disk full errors
+               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;
+       
+               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);
+                                       }
+                               }
+                               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
+                       }
+                       
+                       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);
+                       
+                       // 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);
+                               }
+                       }
+               }
+               catch (const char* msg) {
+                       fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
+                       return 1;
+               }
+               
+               return 0;
+       }
+}
+
+
+
index 61f49ef3eb93bad5e8f63039040732947143511d..7a84b13b773fa3b69330bd986b81ba71c2d2025c 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-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/mman.h>
 #include <sys/param.h>
 #include <sys/mount.h>
+#include <libkern/OSAtomic.h>
 
 #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::fgTotalRebaseFixups = 0;
 uint32_t                                                               ImageLoader::fgTotalBindFixups = 0;
+uint32_t                                                               ImageLoader::fgTotalBindSymbolsResolved = 0;
+uint32_t                                                               ImageLoader::fgTotalBindImageSearches = 0;
 uint32_t                                                               ImageLoader::fgTotalLazyBindFixups = 0;
 uint32_t                                                               ImageLoader::fgTotalPossibleLazyBindFixups = 0;
+uint32_t                                                               ImageLoader::fgTotalSegmentsMapped = 0;
+uint64_t                                                               ImageLoader::fgTotalBytesMapped = 0;
+uint64_t                                                               ImageLoader::fgTotalBytesPreFetched = 0;
 uint64_t                                                               ImageLoader::fgTotalLoadLibrariesTime;
 uint64_t                                                               ImageLoader::fgTotalRebaseTime;
 uint64_t                                                               ImageLoader::fgTotalBindTime;
-uint64_t                                                               ImageLoader::fgTotalNotifyTime;
 uint64_t                                                               ImageLoader::fgTotalInitTime;
 uintptr_t                                                              ImageLoader::fgNextSplitSegAddress = 0x90000000;
-uintptr_t                                                              Segment::fgNextNonSplitSegAddress = 0x8F000000;
+uint16_t                                                               ImageLoader::fgLoadOrdinal = 0;
+uintptr_t                                                              Segment::fgNextPIEDylibAddress = 0;
 
 
-
-__attribute__((noreturn))
-void throwf(const char* format, ...) 
-{
-       va_list list;
-       char*   p;
-       va_start(list, format);
-       vasprintf(&p, format, list);
-       va_end(list);
-       
-       const char*     t = p;
-       throw t;
-}
-
 void ImageLoader::init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate)
 {
        fPathHash = 0;
-       fPath = NULL;
-       if ( path != NULL )
-               this->setPath(path);
+       fPath = path;
        fLogicalPath = NULL;
        fDevice = device;
        fInode = inode;
        fLastModified = modDate;
        fOffsetInFatFile = offsetInFat;
-       //fSegments = NULL;
        fLibraries = NULL;
        fLibrariesCount = 0;
-       fReferenceCount = 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;
-       fLibrariesLoaded = false;
-       fBased = false;
-       fBoundAllNonLazy = false;
-       fBoundAllLazy = false;
+       fRegisteredDOF = false;
+#if IMAGE_NOTIFY_SUPPORT
        fAnnounced = false;
-       fInitialized = false;
-       fNextAddImageIndex = 0;
+#endif
+       fAllLazyPointersBound = false;
+       fBeingRemoved = false;
+       fPathOwnedByImage = false;
+#if RECURSIVE_INITIALIZER_LOCK
+       fInitializerRecursiveLock = NULL;
+#else
+       fInitializerLock = 0;
+#endif
+       if ( fPath != NULL )
+               fPathHash = hash(fPath);
 }
 
 
@@ -107,29 +115,77 @@ ImageLoader::ImageLoader(const char* moduleName)
 
 ImageLoader::~ImageLoader()
 {
-       // need to read up on STL and see if this is right way to destruct vector contents
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               delete seg;
-       }
-       if ( fPath != NULL ) 
+       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--;
+               }
+               delete fDynamicReferences;
+       }
+}
+
+void ImageLoader::setMapped(const LinkContext& context)
+{
+       fState = dyld_image_state_mapped;
+       context.notifySingle(dyld_image_state_mapped, this->machHeader(), fPath, fLastModified);
+}
+
+void ImageLoader::addDynamicReference(const ImageLoader* target)
+{
+       if ( fDynamicReferences == NULL )
+               fDynamicReferences = new std::set<const ImageLoader*>();
+       if ( fDynamicReferences->count(target) == 0 ) { 
+               fDynamicReferences->insert(target);
+               const_cast<ImageLoader*>(target)->fDynamicReferenceCount++;
+       }
+       //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
+}
+
+int ImageLoader::compare(const ImageLoader* right) const
+{
+       if ( this->fDepth == right->fDepth ) {
+               if ( this->fLoadOrder == right->fLoadOrder )
+                       return 0;
+               else if ( this->fLoadOrder < right->fLoadOrder )
+                       return -1;
+               else
+                       return 1;
+       }
+       else {
+               if ( this->fDepth < right->fDepth )
+                       return -1;
+               else
+                       return 1;
+       }
 }
 
-                       
 void ImageLoader::setPath(const char* path)
 {
-       if ( fPath != NULL ) {
-               // if duplicate path, do nothing
-               if ( strcmp(path, fPath) == 0 )
-                       return;
+       if ( fPathOwnedByImage && (fPath != NULL) ) 
                delete [] fPath;
-       }
        fPath = new char[strlen(path)+1];
        strcpy((char*)fPath, path);
+       fPathOwnedByImage = true;  // delete fPath when this image is destructed
+       fPathHash = hash(fPath);
+}
+
+void ImageLoader::setPathUnowned(const char* path)
+{
+       if ( fPathOwnedByImage && (fPath != NULL) ) {
+               delete [] fPath;
+       }
+       fPath = path;
+       fPathOwnedByImage = false;  
        fPathHash = hash(fPath);
 }
 
@@ -202,10 +258,6 @@ uint64_t ImageLoader::getOffsetInFatFile() const
 void ImageLoader::setLeaveMapped()
 {
        fLeaveMapped = true;
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               fSegments[i]->setUnMapWhenDestructed(false);
-       }
 }
 
 void ImageLoader::setHideExports(bool hide)
@@ -220,20 +272,21 @@ bool ImageLoader::hasHiddenExports() const
 
 bool ImageLoader::isLinked() const
 {
-       return fBoundAllNonLazy;
+       return (fState >= dyld_image_state_bound);
 }
 
-time_t ImageLoader::lastModified()
+time_t ImageLoader::lastModified() const
 {
        return fLastModified;
 }
 
 bool ImageLoader::containsAddress(const void* addr) const
 {
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               const uint8_t* start = (const uint8_t*)seg->getActualLoadAddress();
+       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() )
                        return true;
@@ -241,45 +294,61 @@ bool ImageLoader::containsAddress(const void* addr) const
        return false;
 }
 
-void ImageLoader::addMappedRegions(RegionsVector& regions) 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();
+               if ( (start <= segStart) && (segStart < end) )
+                       return true;
+               if ( (start <= segEnd) && (segEnd < end) )
+                       return true;
+               if ( (segStart < start) && (end < segEnd) )
+                       return true;
+       }
+       return false;
+}
+
+void ImageLoader::getMappedRegions(MappedRegion*& regions) const
 {
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
+       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
+               Segment* seg = *it;
                MappedRegion region;
-               region.address = seg->getActualLoadAddress();
+               region.address = seg->getActualLoadAddress(this);
                region.size = seg->getSize();
-               regions.push_back(region);
+               *regions++ = region;
        }
 }
 
 
-void ImageLoader::incrementReferenceCount()
+static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur)
 {
-       ++fReferenceCount;
+       for (const ImageLoader** p = dsiStart; p < dsiCur; ++p)
+               if ( *p == image )
+                       return false;
+       return true;
 }
 
-bool ImageLoader::decrementReferenceCount()
-{
-       return ( --fReferenceCount == 0 );
-}
 
 // private method that handles circular dependencies by only search any image once
-const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name, std::set<const ImageLoader*>& dontSearchImages, ImageLoader** foundIn) const
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name, 
+                       const ImageLoader** dsiStart, const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const
 {
        const ImageLoader::Symbol* sym;
+       
        // search self
-       if ( dontSearchImages.count(this) == 0 ) {
+       if ( notInImgageList(this, dsiStart, dsiCur) ) {
                sym = this->findExportedSymbol(name, NULL, false, foundIn);
                if ( sym != NULL )
                        return sym;
-               dontSearchImages.insert(this);
+               *dsiCur++ = this;
        }
 
        // search directly dependent libraries
        for (uint32_t i=0; i < fLibrariesCount; ++i) {
                ImageLoader* dependentImage = fLibraries[i].image;
-               if ( (dependentImage != NULL) && (dontSearchImages.count(dependentImage) == 0) ) {
+               if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
                        const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, NULL, false, foundIn);
                        if ( sym != NULL )
                                return sym;
@@ -289,11 +358,11 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcep
        // search indirectly dependent libraries
        for (uint32_t i=0; i < fLibrariesCount; ++i) {
                ImageLoader* dependentImage = fLibraries[i].image;
-               if ( (dependentImage != NULL) && (dontSearchImages.count(dependentImage) == 0) ) {
-                       const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
+               if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
+                       *dsiCur++ = dependentImage; 
+                       const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dsiStart, dsiCur, dsiEnd, foundIn);
                        if ( sym != NULL )
                                return sym;
-                       dontSearchImages.insert(dependentImage);
                }
        }
 
@@ -301,90 +370,132 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcep
 }
 
 
-const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, ImageLoader** foundIn) const
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
 {
-       std::set<const ImageLoader*> dontSearchImages;
-       dontSearchImages.insert(this);  // don't search this image
-       return this->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
+       unsigned int imageCount = context.imageCount();
+       const ImageLoader* dontSearchImages[imageCount];
+       dontSearchImages[0] = this; // don't search this image
+       const ImageLoader** cur = &dontSearchImages[1];
+       return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
 }
 
-const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, ImageLoader** foundIn) const
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
 {
-       std::set<const ImageLoader*> dontSearchImages;
-       return this->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
+       unsigned int imageCount = context.imageCount();
+       const ImageLoader* dontSearchImages[imageCount];
+       const ImageLoader** cur = &dontSearchImages[0];
+       return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
 }
 
 
-void ImageLoader::link(const LinkContext& context, BindingLaziness bindness, InitializerRunning inits, uint32_t notifyCount)
+void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
 {
-       uint64_t t1 = mach_absolute_time();
-       this->recursiveLoadLibraries(context);
+       //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
+       
+       uint64_t t0 = mach_absolute_time();
+       this->recursiveLoadLibraries(context,loaderRPaths);
+       context.notifyBatch(dyld_image_state_dependents_mapped);
        
+       // we only do the loading step for preflights
+       if ( preflightOnly )
+               return;
+               
+       uint64_t t1 = mach_absolute_time();
+       context.clearAllDepths();
+       this->recursiveUpdateDepth(context.imageCount());
+
        uint64_t t2 = mach_absolute_time();
        this->recursiveRebase(context);
+       context.notifyBatch(dyld_image_state_rebased);
        
        uint64_t t3 = mach_absolute_time();
-       this->recursiveBind(context, bindness);
-       
+       this->recursiveBind(context, forceLazysBound);
+       context.notifyBatch(dyld_image_state_bound);
+
        uint64_t t4 = mach_absolute_time();     
-       this->recursiveImageNotification(context, notifyCount); 
-       
-       if ( (inits == kRunInitializers) || (inits == kDontRunInitializersButTellObjc) ) {
-               std::vector<ImageLoader*>       newImages;
-               this->recursiveImageAnnouncement(context, newImages);    // build bottom up list images being added
-               context.notifyAdding(newImages);        // tell gdb or anyone who cares about these
-       }
+       std::vector<DOFInfo> dofs;
+       this->recursiveGetDOFSections(context, dofs);
+       context.registerDOFs(dofs);
+
        
-       uint64_t t5 = mach_absolute_time();
-       if ( inits == kRunInitializers ) {
-               this->recursiveInitialization(context);
-               uint64_t t6 = mach_absolute_time();
-               fgTotalInitTime += t6 - t5;
-       }
-       fgTotalLoadLibrariesTime += t2 - t1;
+       fgTotalLoadLibrariesTime += t1 - t0;
        fgTotalRebaseTime += t3 - t2;
        fgTotalBindTime += t4 - t3;
-       fgTotalNotifyTime += t5 - t4;
+       
+       // done with initial dylib loads
+       Segment::fgNextPIEDylibAddress = 0;
+}
+
+
+void ImageLoader::printReferenceCounts()
+{
+       dyld::log("      dlopen=%d, static=%d, dynamic=%d for %s\n", 
+                               fDlopenReferenceCount, fStaticReferenceCount, fDynamicReferenceCount, getPath() );
 }
 
 
-// only called pre-main on main executable
-// if crt.c is ever cleaned up, this could go away
+bool ImageLoader::decrementDlopenReferenceCount() 
+{
+       if ( fDlopenReferenceCount == 0 )
+               return true;
+       --fDlopenReferenceCount;
+       return false;
+}
+
 void ImageLoader::runInitializers(const LinkContext& context)
 {
-               std::vector<ImageLoader*>       newImages;
-               this->recursiveImageAnnouncement(context, newImages);    // build bottom up list images being added
-               context.notifyAdding(newImages);        // tell gdb or anyone who cares about these
+#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
 
-       this->recursiveInitialization(context);
+       uint64_t t1 = mach_absolute_time();
+       this->recursiveInitialization(context, mach_thread_self());
+       context.notifyBatch(dyld_image_state_initialized);
+       uint64_t t2 = mach_absolute_time();
+       fgTotalInitTime += (t2 - t1);
 }
 
-// called inside _dyld_register_func_for_add_image()
-void ImageLoader::runNotification(const LinkContext& context, uint32_t notifyCount)
+
+void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive)
 {
-       this->recursiveImageNotification(context, notifyCount);
+       if ( ! fAllLazyPointersBound ) {
+               fAllLazyPointersBound = true;
+
+               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);
+                       }
+               }
+               // bind lazys in this image
+               this->doBind(context, true);
+       }
 }
 
 
 intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context)
 {
        // preflight and calculate slide if needed
-       const unsigned int segmentCount = fSegments.size();
        intptr_t slide = 0;
        if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
                bool needsToSlide = false;
                uintptr_t lowAddr = UINTPTR_MAX;
                uintptr_t highAddr = 0;
-               for(unsigned int i=0; i < segmentCount; ++i){
-                       Segment* seg = fSegments[i];
+               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();
+                       const uintptr_t segHigh = (segLow + seg->getSize() + 4095) & -4096;
                        if ( segLow < lowAddr )
                                lowAddr = segLow;
                        if ( segHigh > highAddr )
                                highAddr = segHigh;
                                
-                       if ( context.slideAndPackDylibs || !seg->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
+                       if ( !seg->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
                                needsToSlide = true;
                }
                if ( needsToSlide ) {
@@ -394,8 +505,8 @@ intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context)
                }
        } 
        else if ( ! this->segmentsCanSlide() ) {
-               for(unsigned int i=0; i < segmentCount; ++i){
-                       Segment* seg = fSegments[i];
+               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()) )
@@ -412,42 +523,35 @@ intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context)
 void ImageLoader::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
 {
        if ( context.verboseMapping )
-               fprintf(stderr, "dyld: Mapping %s\n", this->getPath());
+               dyld::log("dyld: Mapping %s\n", this->getPath());
        // find address range for image
        intptr_t slide = this->assignSegmentAddresses(context);
        // map in all segments
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               seg->map(fd, offsetInFat, slide, context);              
+       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);
-       
-       // now that it is mapped and slide is set, mark that we should unmap it when done
-       for(unsigned int i=0; i < segmentCount; ++i){
-               fSegments[i]->setUnMapWhenDestructed(true);
-       }
 }
 
 void ImageLoader::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
 {
        if ( context.verboseMapping )
-               fprintf(stderr, "dyld: Mapping memory %p\n", memoryImage);
+               dyld::log("dyld: Mapping memory %p\n", memoryImage);
        // find address range for image
        intptr_t slide = this->assignSegmentAddresses(context);
        // map in all segments
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               seg->map(memoryImage, slide, context);          
+       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(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               seg->setPermissions();          
+       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
+               Segment* seg = *it;
+               seg->setPermissions(context, this);             
        }
 }
 
@@ -457,35 +561,81 @@ bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
 }
 
 
-void ImageLoader::recursiveLoadLibraries(const LinkContext& context)
+unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
+{
+       // the purpose of this phase is to make the images sortable such that 
+       // in a sort list of images, every image that an image depends on
+       // occurs in the list before it.
+       if ( fDepth == 0 ) {
+               // break cycles
+               fDepth = 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);
+                               if ( d < minDependentDepth )
+                                       minDependentDepth = d;
+                       }
+               }
+       
+               // make me less deep then all my dependents
+               fDepth = minDependentDepth - 1;
+       }
+       
+       return fDepth;
+}
+
+
+void ImageLoader::recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths)
 {
-       if ( ! fLibrariesLoaded ) {
+       if ( fState < dyld_image_state_dependents_mapped ) {
                // break cycles
-               fLibrariesLoaded = true;
+               fState = dyld_image_state_dependents_mapped;
                
                // get list of libraries this image needs
                fLibrariesCount = this->doGetDependentLibraryCount();
                fLibraries = new DependentLibrary[fLibrariesCount];
-               this->doGetDependentLibraries(fLibraries);
+               bzero(fLibraries, sizeof(DependentLibrary)*fLibrariesCount);
+               DependentLibraryInfo libraryInfos[fLibrariesCount]; 
+               this->doGetDependentLibraries(libraryInfos);
+               
+               // get list of rpaths that this image adds
+               std::vector<const char*> rpathsFromThisImage;
+               this->getRPaths(context, rpathsFromThisImage);
+               const RPathChain thisRPaths(&loaderRPaths, &rpathsFromThisImage);
                
                // try to load each
                bool canUsePrelinkingInfo = true; 
                for(unsigned int i=0; i < fLibrariesCount; ++i){
                        DependentLibrary& requiredLib = fLibraries[i];
+                       DependentLibraryInfo& requiredLibInfo = libraryInfos[i];
                        try {
-                               requiredLib.image = context.loadLibrary(requiredLib.name, true, this->getPath(), NULL);
+                               bool depNamespace = false;
+                               requiredLib.image = context.loadLibrary(requiredLibInfo.name, true, depNamespace, this->getPath(), &thisRPaths);
                                if ( requiredLib.image == this ) {
                                        // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168 
-                                       requiredLib.image = context.loadLibrary(requiredLib.name, false, NULL, NULL);
+                                       requiredLib.image = context.loadLibrary(requiredLibInfo.name, false, depNamespace, NULL, NULL);
                                        if ( requiredLib.image != this )
-                                               fprintf(stderr, "dyld: warning DYLD_ setting caused circular dependency in %s\n", this->getPath());
+                                               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.checksumMatches = ( actualInfo.checksum == requiredLib.info.checksum );
+                               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);
+                               }
                                // check found library version is compatible
-                               if ( actualInfo.minVersion < requiredLib.info.minVersion ) {
-                                       throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
-                                                       this->getShortName(), requiredLib.info.minVersion >> 16, (requiredLib.info.minVersion >> 8) & 0xff, requiredLib.info.minVersion & 0xff,
+                               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);
                                }
                                // prebinding for this image disabled if any dependent library changed or slid
@@ -493,7 +643,8 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context)
                                        canUsePrelinkingInfo = false;
                                //if ( context.verbosePrebinding ) {
                                //      if ( !requiredLib.checksumMatches )
-                               //              fprintf(stderr, "dyld: checksum mismatch, (%lld v %lld) for %s referencing %s\n", requiredLib.info.checksum, actualInfo.checksum, this->getPath(),      requiredLib.image->getPath());          
+                               //              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());         
                                //}
@@ -501,13 +652,9 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context)
                        catch (const char* msg) {
                                //if ( context.verbosePrebinding )
                                //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), requiredLib.image->getPath());            
-                               if ( requiredLib.required ) {
-                                       const char* formatString = "Library not loaded: %s\n  Referenced from: %s\n  Reason: %s";
-                                       const char* referencedFrom = this->getPath();
-                                       char buf[strlen(requiredLib.name)+strlen(referencedFrom)+strlen(formatString)+strlen(msg)+2];
-                                       sprintf(buf, formatString, requiredLib.name, referencedFrom, msg);
-                                       fLibrariesLoaded = false;
-                                       throw strdup(buf);  // this is a leak if exception doesn't halt program
+                               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;
@@ -518,13 +665,9 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context)
 
                // tell each to load its dependents
                for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo = fLibraries[i];
-                       if ( libInfo.image != NULL ) {  
-                               libInfo.isSubFramework = libInfo.image->isSubframeworkOf(context, this);
-                               libInfo.isReExported = libInfo.isSubFramework || this->hasSubLibrary(context, libInfo.image);
-                               //if ( libInfo.isReExported  )
-                               //      fprintf(stderr, "%s re-exports %s\n", strrchr(this->getPath(), '/'), strrchr(libInfo.image->getPath(),'/'));
-                               libInfo.image->recursiveLoadLibraries(context);
+                       DependentLibrary& lib = fLibraries[i];
+                       if ( lib.image != NULL ) {      
+                               lib.image->recursiveLoadLibraries(context, thisRPaths);
                        }
                }
                
@@ -539,14 +682,20 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context)
                        }
                }
                
+               // free rpaths (getRPaths() malloc'ed each string)
+               for(std::vector<const char*>::iterator it=rpathsFromThisImage.begin(); it != rpathsFromThisImage.end(); ++it) {
+                       const char* str = *it;
+                       free((void*)str);
+               }
+               
        }
 }
 
 void ImageLoader::recursiveRebase(const LinkContext& context)
 { 
-       if ( ! fBased ) {
+       if ( fState < dyld_image_state_rebased ) {
                // break cycles
-               fBased = true;
+               fState = dyld_image_state_rebased;
                
                try {
                        // rebase lower level libraries first
@@ -558,11 +707,14 @@ void ImageLoader::recursiveRebase(const LinkContext& context)
                                
                        // rebase this image
                        doRebase(context);
+                       
+                       // notify
+                       context.notifySingle(dyld_image_state_rebased, this->machHeader(), fPath, fLastModified);
                }
                catch (const char* msg) {
                        // this image is not rebased
-                       fBased = false;
-                       throw msg;
+                       fState = dyld_image_state_dependents_mapped;
+                       throw;
                }
        }
 }
@@ -570,89 +722,43 @@ void ImageLoader::recursiveRebase(const LinkContext& context)
 
 
 
-void ImageLoader::recursiveBind(const LinkContext& context, BindingLaziness bindness)
+void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound)
 {
-       // normally just non-lazy pointers are bound up front,
-       // but DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound up from
-       // and some dyld API's bind all lazys at runtime
-       bool nonLazy = false;
-       bool lazy = false;
-       switch( bindness ) {
-               case kNonLazyOnly:
-                       nonLazy = true;
-                       break;
-               case kLazyAndNonLazy:
-                       nonLazy = true;
-                       lazy = true;
-                       break;
-               case kLazyOnly:
-               case kLazyOnlyNoDependents:
-                       lazy = true;
-                       break;
-       }
-       const bool doNonLazy = nonLazy && !fBoundAllNonLazy;
-       const bool doLazy = lazy && !fBoundAllLazy;
-       if ( doNonLazy || doLazy ) {
+       // Normally just non-lazy pointers are bound immediately.
+       // The exceptions are:
+       //   1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately
+       //   2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately
+       if ( fState < dyld_image_state_bound ) {
                // break cycles
-               bool oldBoundAllNonLazy = fBoundAllNonLazy;
-               bool oldBoundAllLazy = fBoundAllLazy;
-               fBoundAllNonLazy = fBoundAllNonLazy || nonLazy;
-               fBoundAllLazy = fBoundAllLazy || lazy;
-               
+               fState = dyld_image_state_bound;
+       
                try {
                        // bind lower level libraries first
-                       if ( bindness != kLazyOnlyNoDependents ) {
-                               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                                       DependentLibrary& libInfo = fLibraries[i];
-                                       if ( libInfo.image != NULL )
-                                               libInfo.image->recursiveBind(context, bindness);
-                               }
+                       for(unsigned int i=0; i < fLibrariesCount; ++i){
+                               DependentLibrary& libInfo = fLibraries[i];
+                               if ( libInfo.image != NULL )
+                                       libInfo.image->recursiveBind(context, forceLazysBound);
                        }
                        // bind this image
-                       if ( doLazy && !doNonLazy )
-                               doBind(context, kLazyOnly);     
-                       else if ( !doLazy && doNonLazy )
-                               doBind(context, kNonLazyOnly);
-                       else 
-                               doBind(context, kLazyAndNonLazy);
+                       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);
                }
                catch (const char* msg) {
                        // restore state
-                       fBoundAllNonLazy = oldBoundAllNonLazy;
-                       fBoundAllLazy = oldBoundAllLazy;
-                       throw msg;
-               }
-       }
-}
-
-//
-// This is complex because _dyld_register_func_for_add_image() is defined to not only
-// notify you of future image loads, but also of all currently loaded images.  Therefore
-// each image needs to track that all add-image-funcs have been notified about it.
-// Since add-image-funcs cannot be removed, each has a unique index and each image
-// records the thru which index notificiation has already been done.
-//
-void ImageLoader::recursiveImageNotification(const LinkContext& context, uint32_t addImageCount)
-{
-       if ( fNextAddImageIndex < addImageCount ) {
-               // break cycles
-               const uint32_t initIndex = fNextAddImageIndex;
-               fNextAddImageIndex = addImageCount;
-       
-               // notify all requestors about this image
-               context.imageNotification(this, initIndex);
-       
-               // notify about lower level libraries first
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo = fLibraries[i];
-                       if ( libInfo.image != NULL )
-                               libInfo.image->recursiveImageNotification(context, addImageCount);
+                       fState = dyld_image_state_rebased;
+                       throw;
                }
        }
 }
 
 
-void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, std::vector<ImageLoader*>& newImages)
+#if IMAGE_NOTIFY_SUPPORT
+void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages)
 {
        if ( ! fAnnounced ) {
                // break cycles
@@ -665,199 +771,110 @@ void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, std::ve
                                libInfo.image->recursiveImageAnnouncement(context, newImages);
                }
                
-               // add to list of images to notify gdb about
-               newImages.push_back(this);
-               //fprintf(stderr, "next size = %d\n", newImages.size());
+               // add to list of images to notify about
+               *newImages++ = this;
+               //dyld::log("next size = %d\n", newImages.size());
                
                // remember that this image wants to be notified about other images
                 if ( this->hasImageNotification() )
                        context.addImageNeedingNotification(this);
        }
 }
+#endif
 
+void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs)
+{
+       if ( ! fRegisteredDOF ) {
+               // break cycles
+               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);
+               }
+               this->doGetDOFSections(context, dofs);
+       }
+}
+
+
+void ImageLoader::recursiveSpinLock(recursive_lock& rlock)
+{
+       // try to set image's ivar fInitializerRecursiveLock to point to this lock_info
+       // keep trying until success (spin)
+       while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL, &rlock, (void**)&fInitializerRecursiveLock) ) {
+               // if fInitializerRecursiveLock already points to a different lock_info, if it is for
+               // the same thread we are on, the increment the lock count, otherwise continue to spin
+               if ( (fInitializerRecursiveLock != NULL) && (fInitializerRecursiveLock->thread == rlock.thread) )
+                       break;
+       }
+       ++(fInitializerRecursiveLock->count); 
+}
+
+void ImageLoader::recursiveSpinUnLock()
+{
+       if ( --(fInitializerRecursiveLock->count) == 0 )
+               fInitializerRecursiveLock = NULL;
+}
 
 
-void ImageLoader::recursiveInitialization(const LinkContext& context)
+void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread)
 {
-       if ( ! fInitialized ) {
+#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
-               fInitialized = true;
+               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];
-                               if ( libInfo.image != NULL )
-                                       libInfo.image->recursiveInitialization(context);
+                               // don't try to initialize stuff "above" me
+                               if ( (libInfo.image != NULL) && (libInfo.image->fDepth >= fDepth) )
+                                       libInfo.image->recursiveInitialization(context, this_thread);
                        }
                        
                        // record termination order
                        if ( this->needsTermination() )
                                context.terminationRecorder(this);
                        
+                       // 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);
+
                        // 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);
                }
                catch (const char* msg) {
                        // this image is not initialized
-                       fInitialized = false;
-                       throw msg;
-               }
-       }
-}
-
-void ImageLoader::reprebindCommit(const LinkContext& context, bool commit, bool unmapOld)
-{
-       // do nothing on unprebound images
-       if ( ! this->isPrebindable() )
-               return;
-
-       // do nothing if prebinding is up to date
-       if ( this->usablePrebinding(context) )
-               return;
-               
-       // make sure we are not replacing a symlink with a file
-       char realFilePath[PATH_MAX];
-       if ( realpath(this->getPath(), realFilePath) == NULL ) {
-               throwf("realpath() failed on %s, errno=%d", this->getPath(), errno);
-       }
-       // recreate temp file name
-       char tempFilePath[PATH_MAX];
-       char suffix[64];
-       sprintf(suffix, "_redoprebinding%d", getpid());
-       ImageLoader::addSuffix(realFilePath, suffix, tempFilePath);
-
-       if ( commit ) {
-               // all files successfully reprebound, so do swap
-               int result = rename(tempFilePath, realFilePath);
-               if ( result != 0 ) {
-                       // if there are two dylibs with the same install path, the second will fail to prebind
-                       // because the _redoprebinding temp file is gone.  In that case, log and go on.
-                       if ( errno == ENOENT )
-                               fprintf(stderr, "update_prebinding: temp file missing: %s\n", tempFilePath);
-                       else
-                               throwf("can't swap temporary re-prebound file: rename(%s,%s) returned errno=%d", tempFilePath, realFilePath, errno);
-               }
-               else if ( unmapOld ) {
-                       this->prebindUnmap(context);
+                       fState = oldState;
+               #if RECURSIVE_INITIALIZER_LOCK
+                       recursiveSpinUnLock();
+               #else
+                       _spin_unlock(&fInitializerLock);
+               #endif
+                       throw;
                }
        }
-       else {
-               // something went wrong during prebinding, delete the temp files
-               unlink(tempFilePath);
-       }
-}
-
-uint64_t ImageLoader::reprebind(const LinkContext& context, time_t timestamp)
-{
-       // do nothing on unprebound images
-       if ( ! this->isPrebindable() )
-               return INT64_MAX;
-
-       // do nothing if prebinding is up to date
-       if ( this->usablePrebinding(context) ) {
-               if ( context.verbosePrebinding )
-                       fprintf(stderr, "dyld: no need to re-prebind: %s\n", this->getPath());
-               return INT64_MAX;
-       }
-       // recreate temp file name
-       char realFilePath[PATH_MAX];
-       if ( realpath(this->getPath(), realFilePath) == NULL ) {
-               throwf("realpath() failed on %s, errno=%d", this->getPath(), errno);
-       }
-       char tempFilePath[PATH_MAX];
-       char suffix[64];
-       sprintf(suffix, "_redoprebinding%d", getpid());
-       ImageLoader::addSuffix(realFilePath, suffix, tempFilePath);
-
-       // make copy of file and map it in
-       uint8_t* fileToPrebind;
-       uint64_t fileToPrebindSize;
-       uint64_t freespace = this->copyAndMap(tempFilePath, &fileToPrebind, &fileToPrebindSize);
-
-       // do format specific prebinding
-       this->doPrebinding(context, timestamp, fileToPrebind);
        
-       // flush and swap files
-       int result = msync(fileToPrebind, fileToPrebindSize, MS_ASYNC);
-       if ( result != 0 )
-               throw "error syncing re-prebound file";
-       result = munmap(fileToPrebind, fileToPrebindSize);
-       if ( result != 0 )
-               throw "error unmapping re-prebound file";
-
-       // log
-       if ( context.verbosePrebinding )
-               fprintf(stderr, "dyld: re-prebound: %p %s\n", this->machHeader(), this->getPath());
-       
-       return freespace;
-}
-
-uint64_t ImageLoader::copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize) 
-{
-       // reopen dylib 
-       int src = open(this->getPath(), O_RDONLY);      
-       if ( src == -1 )
-               throw "can't open image";
-       struct stat stat_buf;
-       if ( fstat(src, &stat_buf) == -1)
-               throw "can't stat image";
-       if ( stat_buf.st_mtime != fLastModified )
-               throw "image file changed since it was loaded";
-               
-       // create new file with all same permissions to hold copy of dylib 
-       unlink(tempFile);
-       int dst = open(tempFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode); 
-       if ( dst == -1 )
-               throw "can't create temp image";
-
-       // mark source as "don't cache"
-       (void)fcntl(src, F_NOCACHE, 1);
-       // we want to cache the dst because we are about to map it in and modify it
-       
-       // copy permission bits
-       if ( chmod(tempFile, stat_buf.st_mode & 07777) == -1 )
-               throwf("can't chmod temp image.  errno=%d for %s", errno, this->getPath());
-       if ( chown(tempFile, stat_buf.st_uid, stat_buf.st_gid) == -1)
-               throwf("can't chown temp image.  errno=%d for %s", errno, this->getPath());
-                 
-       // copy contents
-       ssize_t len;
-       const uint32_t kBufferSize = 128*1024;
-       static uint8_t* buffer = NULL;
-       if ( buffer == NULL ) {
-               vm_address_t addr = 0;
-               if ( vm_allocate(mach_task_self(), &addr, kBufferSize, true /*find range*/) == KERN_SUCCESS )
-                       buffer = (uint8_t*)addr;
-               else
-                       throw "can't allcoate copy buffer";
-       }
-       while ( (len = read(src, buffer, kBufferSize)) > 0 ) {
-               if ( write(dst, buffer, len) == -1 )
-                       throwf("write failure copying dylib errno=%d for %s", errno, this->getPath());
-       }
-       
-       // map in dst file
-       *fileToPrebindSize = stat_buf.st_size - fOffsetInFatFile; // this may map in too much, but it does not matter
-       *fileToPrebind = (uint8_t*)mmap(NULL, *fileToPrebindSize, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, dst, fOffsetInFatFile);
-       if ( *fileToPrebind == (uint8_t*)(-1) )
-               throw "can't mmap temp image";
-               
-       // get free space remaining on dst volume
-       struct statfs statfs_buf;
-       if ( fstatfs(dst, &statfs_buf) != 0 )
-               throwf("can't fstatfs(), errno=%d for %s", errno, tempFile);
-       uint64_t freespace = (uint64_t)statfs_buf.f_bavail * (uint64_t)statfs_buf.f_bsize;
-       
-       // closing notes:  
-       //              ok to close file after mapped in
-       //              ok to throw above without closing file because the throw will terminate update_prebinding
-       int result1 = close(dst);
-       int result2 = close(src);
-       if ( (result1 != 0) || (result2 != 0) )
-               throw "can't close file";
-               
-       return freespace;
+#if RECURSIVE_INITIALIZER_LOCK
+       recursiveSpinUnLock();
+#else
+       _spin_unlock(&fInitializerLock);
+#endif
 }
 
 
@@ -875,49 +892,62 @@ static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
                uint32_t milliSeconds = milliSecondsTimeTen/10;
                uint32_t percentTimesTen = (partTime*1000)/totalTime;
                uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
+               dyld::log("%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
        }
        else {
                uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
                uint32_t seconds = secondsTimeTen/10;
                uint32_t percentTimesTen = (partTime*1000)/totalTime;
                uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
+               dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
        }
 }
 
 static char* commatize(uint64_t in, char* out)
 {
-       char* result = out;
-       char rawNum[30];
-       sprintf(rawNum, "%llu", in);
-       const int rawNumLen = strlen(rawNum);
-       for(int i=0; i < rawNumLen-1; ++i) {
-               *out++ = rawNum[i];
-               if ( ((rawNumLen-i) % 3) == 1 )
-                       *out++ = ',';
+       uint64_t div10 = in / 10;
+       uint8_t delta = in - div10*10;
+       char* s = &out[32];
+       int digitCount = 1;
+       *s = '\0';
+       *(--s) = '0' + delta;
+       in = div10;
+       while ( in != 0 ) {
+               if ( (digitCount % 3) == 0 )
+                       *(--s) = ',';
+               div10 = in / 10;
+               delta = in - div10*10;
+               *(--s) = '0' + delta;
+               in = div10;
+               ++digitCount;
        }
-       *out++ = rawNum[rawNumLen-1];
-       *out = '\0';
-       return result;
-} 
+       return s;
+}
+
 
 
 void ImageLoader::printStatistics(unsigned int imageCount)
 {
-       uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalNotifyTime + fgTotalInitTime;
+       uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalInitTime;
        char commaNum1[40];
        char commaNum2[40];
 
        printTime("total time", totalTime, totalTime);
-       fprintf(stderr, "total images loaded:  %d (%d used prebinding)\n", imageCount, fgImagesWithUsedPrebinding);
+       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);
-       fprintf(stderr, "total rebase fixups:  %s\n", commatize(fgTotalRebaseFixups, commaNum1));
+       dyld::log("total rebase fixups:  %s\n", commatize(fgTotalRebaseFixups, commaNum1));
        printTime("total rebase fixups time", fgTotalRebaseTime, totalTime);
-       fprintf(stderr, "total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1));
+       dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1));
+       if ( fgTotalBindSymbolsResolved != 0 ) {
+               uint32_t avgTimesTen = (fgTotalBindImageSearches * 10) / fgTotalBindSymbolsResolved;
+               uint32_t avgInt = fgTotalBindImageSearches / fgTotalBindSymbolsResolved;
+               uint32_t avgTenths = avgTimesTen - (avgInt*10);
+               dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n", 
+                               commatize(fgTotalBindSymbolsResolved, commaNum1), avgInt, avgTenths);
+       }
        printTime("total binding fixups time", fgTotalBindTime, totalTime);
-       fprintf(stderr, "total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
-       printTime("total notify time time", fgTotalNotifyTime, 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);
 }
 
@@ -952,7 +982,7 @@ void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
 }
 
 
-void Segment::map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader::LinkContext& context)
+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();
@@ -966,15 +996,26 @@ void Segment::map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const Ima
                if ( this->writeable() )
                        protection   |= PROT_WRITE;
        }
-       void* loadAddress = mmap(requestedLoadAddress, size, protection, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
-       if ( loadAddress == ((void*)(-1)) )
-               throwf("mmap() error %d at address=0x%08lX, size=0x%08lX in Segment::map() mapping %s", errno, (uintptr_t)requestedLoadAddress, (uintptr_t)size, this->getImage()->getPath());
-       
+#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 )
-               fprintf(stderr, "%18s at %p->%p\n", this->getName(), loadAddress, (char*)loadAddress+this->getFileSize()-1);
+               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::LinkContext& context)
+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();
@@ -984,10 +1025,10 @@ void Segment::map(const void* memoryImage, intptr_t slide, const ImageLoader::Li
                throw "can't map segment";
                
        if ( context.verboseMapping )
-               fprintf(stderr, "%18s at %p->%p\n", this->getName(), (char*)loadAddress, (char*)loadAddress+this->getFileSize()-1);
+               dyld::log("%18s at %p->%p\n", this->getName(), (char*)loadAddress, (char*)loadAddress+this->getFileSize()-1);
 }
 
-void Segment::setPermissions()
+void Segment::setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image)
 {
        vm_prot_t protection = 0;
        if ( !this->unaccessible() ) {
@@ -998,22 +1039,33 @@ void Segment::setPermissions()
                if ( this->writeable() )
                        protection   |= VM_PROT_WRITE;
        }
-       vm_address_t addr = this->getActualLoadAddress();
+       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()
+void Segment::tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image)
 {
-       vm_address_t addr = this->getActualLoadAddress();
+       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, VM_PROT_WRITE | VM_PROT_READ);
+       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' : '.' );
+       }
 }
 
 
@@ -1027,18 +1079,20 @@ uintptr_t Segment::reserveAnAddressRange(size_t length, const ImageLoader::LinkC
 {
        vm_address_t addr = 0;
        vm_size_t size = length;
-       if ( context.slideAndPackDylibs ) {
-               addr = (fgNextNonSplitSegAddress - length) & (-4096); // page align
-               kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*use this range*/);
-               if ( r != KERN_SUCCESS ) 
-                       throw "out of address space";
-               fgNextNonSplitSegAddress = addr;
-       }
-       else {
-               kern_return_t r = vm_allocate(mach_task_self(), &addr, size, true /*find range*/);
-               if ( r != KERN_SUCCESS ) 
-                       throw "out of address space";
+       // 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;
 }
 
index 4a8a9d89cdc33ac1d3b93f70a1619728d8278971..e7795d0f6bc631e7070a8293d265cb18f1ea5708 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include <sys/types.h>
 #include <mach/mach_time.h> // struct mach_timebase_info
+#include <mach/mach_init.h> // struct mach_thread_self
 #include <stdint.h>
 #include <vector>
 #include <set>
 
-#include "mach-o/dyld_gdb.h"
+#include "mach-o/dyld_images.h"
+#include "mach-o/dyld_priv.h"
+
+
+#define SPLIT_SEG_SHARED_REGION_SUPPORT 0
+#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__)
+#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__)
+
+
+// utilities
+namespace dyld {
+       extern __attribute__((noreturn)) void throwf(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+       extern void log(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+       extern void warn(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+       extern const char* mkstringf(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+};
+
+
+struct ProgramVars
+{
+       const void*             mh;
+       int*                    NXArgcPtr;
+       const char***   NXArgvPtr;
+       const char***   environPtr;
+       const char**    __prognamePtr;
+};
 
 
-// utility
-__attribute__((noreturn)) void throwf(const char* format, ...);
 
 //
 // ImageLoader is an abstract base class.  To support loading a particular executable
@@ -60,12 +88,9 @@ public:
        static const ReferenceFlags kWeakReference = 1;
        static const ReferenceFlags kTentativeDefinition = 2;
        
-
-       enum BindingLaziness { kNonLazyOnly, kLazyAndNonLazy, kLazyOnly, kLazyOnlyNoDependents };
-       enum InitializerRunning { kDontRunInitializers, kRunInitializers, kDontRunInitializersButTellObjc };
        enum PrebindMode { kUseAllPrebinding, kUseSplitSegPrebinding, kUseAllButAppPredbinding, kUseNoPrebinding };
        enum BindingOptions { kBindingNone, kBindingLazyPointers, kBindingNeverSetLazyPointers };
-       enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion };
+       enum SharedRegionMode { kUseSharedRegion, kUsePrivateSharedRegion, kDontUseSharedRegion, kSharedRegionIsSharedCache };
        
        struct Symbol;  // abstact symbol
 
@@ -73,37 +98,68 @@ public:
                uintptr_t       address;
                size_t          size;
        };
-       typedef std::vector<MappedRegion> RegionsVector;
+
+       struct RPathChain {
+               RPathChain(const RPathChain* n, std::vector<const char*>* p) : next(n), paths(p) {};
+               const RPathChain*                       next;
+               std::vector<const char*>*       paths;
+       };
+
+       struct DOFInfo {
+               void*                           dof;
+               const mach_header*      imageHeader;
+               const char*                     imageShortName;
+       };
 
        struct LinkContext {
-               ImageLoader*    (*loadLibrary)(const char* libraryName, bool search, const char* origin, const char* rpath[]);
-               uint32_t                (*imageNotification)(ImageLoader* image, uint32_t startIndex);
+               ImageLoader*    (*loadLibrary)(const char* libraryName, bool search, bool findDLL, const char* origin, const RPathChain* rpaths);
                void                    (*terminationRecorder)(ImageLoader* image);
-               bool                    (*flatExportFinder)(const char* name, const Symbol** sym, ImageLoader** image);
-               bool                    (*coalescedExportFinder)(const char* name, const Symbol** sym, ImageLoader** image);
+               bool                    (*flatExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
+               bool                    (*coalescedExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
                void                    (*undefinedHandler)(const char* name);
+#if IMAGE_NOTIFY_SUPPORT
                void                    (*addImageNeedingNotification)(ImageLoader* image);
-               void                    (*notifyAdding)(std::vector<ImageLoader*>& images);
-               void                    (*getAllMappedRegions)(RegionsVector&);
+               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                    (*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&);
+#if SUPPORT_OLD_CRT_INITIALIZATION
+               void                    (*setRunInitialzersOldWay)();
+#endif
                BindingOptions  bindingOptions;
                int                             argc;
                const char**    argv;
                const char**    envp;
                const char**    apple;
+               const char*             progname;
+               ProgramVars             programVars;
                ImageLoader*    mainExecutable;
                const char*             imageSuffix;
                PrebindMode             prebindUsage;
                SharedRegionMode sharedRegionMode;
+               bool                    dyldLoadedAtSameAddressNeededBySharedCache; 
+               bool                    preFetchDisabled;
                bool                    prebinding;
                bool                    bindFlat;
-               bool                    slideAndPackDylibs;
+               bool                    linkingMainExecutable;
                bool                    verboseOpts;
                bool                    verboseEnv;
                bool                    verboseMapping;
                bool                    verboseRebase;
                bool                    verboseBind;
                bool                    verboseInit;
+               bool                    verboseDOF;
                bool                    verbosePrebinding;
                bool                    verboseWarnings;
        };
@@ -113,16 +169,15 @@ public:
        
                                                                                // link() takes a newly instantiated ImageLoader and does all 
                                                                                // fixups needed to make it usable by the process
-       void                                                            link(const LinkContext& context, BindingLaziness mode, InitializerRunning inits, uint32_t notifyCount);
+       void                                                            link(const LinkContext& context, bool forceLazysBound, bool preflight, const RPathChain& loaderRPaths);
        
                                                                                // runInitializers() is normally called in link() but the main executable must 
                                                                                // run crt code before initializers
        void                                                            runInitializers(const LinkContext& context);
        
-                                                                               // runNotification() is normally called in link() but the main executable must 
-                                                                               // run crt code before initializers
-       void                                                            runNotification(const LinkContext& context, uint32_t notifyCount);
-               
+                                                                               // called after link() forces all lazy pointers to be bound
+       void                                                            bindAllLazyPointers(const LinkContext& context, bool recursive);
+       
                                                                                // used by dyld to see if a requested library is already loaded (might be symlink)
        bool                                                            statMatch(const struct stat& stat_buf) const;
 
@@ -159,21 +214,21 @@ public:
                                                                                // even if image is deleted, leave segments mapped in
        void                                                            setLeaveMapped();
        
+                                                                               // even if image is deleted, leave segments mapped in
+       bool                                                            leaveMapped() { return fLeaveMapped; }
+
                                                                                // checks if the specifed address is within one of this image's segments
        virtual bool                                            containsAddress(const void* addr) const;
 
+                                                                               // checks if the specifed address range overlaps any of this image's segments
+       virtual bool                                            overlapsWithAddressRange(const void* start, const void* end) const;
+
                                                                                // adds to list of ranges of memory mapped in
-       void                                                            addMappedRegions(RegionsVector& regions) const;
+       void                                                            getMappedRegions(MappedRegion*& region) const;
 
                                                                                // st_mtime from stat() on file
-       time_t                                                          lastModified();
+       time_t                                                          lastModified() const;
 
-                                                                               // image should create prebound version of itself and return freespace remaining on disk
-       uint64_t                                                        reprebind(const LinkContext& context, time_t timestamp);
-       
-                                                                               // if 'commit', the prebound version should be swapped in, otherwise deleted
-       void                                                            reprebindCommit(const LinkContext& context, bool commit, bool unmapOld);
-       
                                                                                // only valid for main executables, returns a pointer its entry point
        virtual void*                                           getMain() const = 0;
        
@@ -183,17 +238,17 @@ public:
                                                                                // dyld API's require each image to have a slide (actual load address minus preferred load address)
        virtual uintptr_t                                       getSlide() const = 0;
        
-                                                                               // dyld API's require each image to have a slide (actual load address minus preferred load address)
-       virtual const void*                                     getBaseAddress() const = 0;
+                                                                               // last address mapped by image
+       virtual const void*                                     getEnd() const = 0;
        
                                                                                // image has exports that participate in runtime coalescing
        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, ImageLoader** foundIn) const = 0;
+       virtual const Symbol*                           findExportedSymbol(const char* name, const void* hint, 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 = 0;
+       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor=NULL) const = 0;
        
                                                                                // gets attributes of the specified exported symbol
        virtual DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const = 0;
@@ -209,11 +264,11 @@ public:
                        
                                                                                // find exported symbol as if imported by this image
                                                                                // used by RTLD_NEXT
-       virtual const Symbol*                           findExportedSymbolInDependentImages(const char* name, ImageLoader** foundIn) const;
+       virtual const Symbol*                           findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const;
        
                                                                                // find exported symbol as if imported by this image
                                                                                // used by RTLD_SELF
-       virtual const Symbol*                           findExportedSymbolInImageOrDependentImages(const char* name, ImageLoader** foundIn) const;
+       virtual const Symbol*                           findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const;
        
                                                                                // gets how many symbols are imported by this image
        virtual uint32_t                                        getImportedSymbolCount() const = 0;
@@ -242,15 +297,17 @@ public:
                                                                                // 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;
                        
@@ -263,9 +320,27 @@ public:
                                                                                // the image is prebindable and its prebinding is valid
        virtual bool                                            usablePrebinding(const LinkContext& context) const = 0;
        
-                                                                               // used to implement refernce counting of images
-       void                                                            incrementReferenceCount();
-       bool                                                            decrementReferenceCount();
+                                                                               // add all RPATH paths this image contains
+       virtual void                                            getRPaths(const LinkContext& context, std::vector<const char*>&) const = 0;
+       
+       
+
+       dyld_image_states                                       getState() { return (dyld_image_states)fState; }
+       
+                                                                               // used to sort images bottom-up
+       int                                                                     compare(const ImageLoader* right) const;
+       
+       void                                                            incrementDlopenReferenceCount() { ++fDlopenReferenceCount; }
+
+       bool                                                            decrementDlopenReferenceCount();
+       
+       void                                                            printReferenceCounts();
+
+       uint32_t                                                        referenceCount() const { return fDlopenReferenceCount + fStaticReferenceCount + fDynamicReferenceCount; }
+
+       bool                                                            neverUnload() const { return fNeverUnload; }
+
+       void                                                            setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
 
                                                                                // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
        static void                                                     printStatistics(unsigned int imageCount);
@@ -274,11 +349,41 @@ public:
        static void                                                     addSuffix(const char* path, const char* suffix, char* result);
        
        static uint32_t                                         hash(const char*);
-       
-       
+               
                        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; }
+                       bool                                            isBeingRemoved() const { return fBeingRemoved; }
+                       
+       
+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:
        // abstract base class so all constructors protected
@@ -289,42 +394,59 @@ protected:
        
 
        struct LibraryInfo {
-               uint64_t                checksum;
+               uint32_t                checksum;
                uint32_t                minVersion;
                uint32_t                maxVersion;
        };
 
        struct DependentLibrary {
-               const char*             name;
                ImageLoader*    image;
-               LibraryInfo             info;
-               bool                    required;
-               bool                    checksumMatches;
-               bool                    isReExported;
-               bool                    isSubFramework;
+               uint32_t                required : 1,
+                                               checksumMatches : 1,
+                                               isReExported : 1,
+                                               isSubFramework : 1;
        };
        
-       typedef void (*Initializer)(int argc, const char* argv[], const char* envp[],const char* apple[]);
+       struct DependentLibraryInfo {
+               const char*                     name;
+               LibraryInfo                     info;
+               bool                            required;
+               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);
        
                                                // 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);
+       void                            recursiveLoadLibraries(const LinkContext& context, 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, BindingLaziness bindness);
-       void                            recursiveImageAnnouncement(const LinkContext& context, std::vector<ImageLoader*>& newImages);
-       void                            recursiveImageNotification(const LinkContext& context, uint32_t addImageCount);
-       void                            recursiveInitialization(const LinkContext& context);
+       void                            recursiveBind(const LinkContext& context, bool forceLazysBound);
+       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);
 
-                                                               // map any segments this image has into memory and build fSegments
-                                                               // this is called before doGetDependentLibraryCount so if metadata is in segments it is mapped in
-       virtual void                            instantiateSegments(const uint8_t* fileData) = 0;
-       
                                                                // return how many libraries this image depends on
        virtual uint32_t                        doGetDependentLibraryCount() = 0;
        
                                                                // fill in information about dependent libraries (array length is doGetDependentLibraryCount())
-       virtual void                            doGetDependentLibraries(DependentLibrary libs[]) = 0;
+       virtual void                            doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
        
                                                                // called on images that are libraries, returns info about itself
        virtual LibraryInfo                     doGetLibraryInfo() = 0;
@@ -333,14 +455,17 @@ protected:
        virtual void                            doRebase(const LinkContext& context) = 0;
        
                                                                // do any symbolic fix ups in this image
-       virtual void                            doBind(const LinkContext& context, BindingLaziness bindness) = 0;
+       virtual void                            doBind(const LinkContext& context, bool forceLazysBound) = 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;
        
                                                                // run any initialization routines in this image
        virtual void                            doInitialization(const LinkContext& context) = 0;
        
-                                                               // write prebinding updates to mapped file fileToPrebind
-       virtual void                            doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind) = 0;
-
                                                                // return if this image has termination routines
        virtual bool                            needsTermination() = 0;
        
@@ -368,18 +493,34 @@ protected:
                                                                // in mach-o a parent library knows name of sub libraries it re-exports..
        virtual bool                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const  = 0;
        
-                                                               // file has been reprebound on disk, unmap this file so original file is released
-       virtual void                            prebindUnmap(const LinkContext& context) = 0;
+                                                               // set fState to dyld_image_state_memory_mapped
+       void                                            setMapped(const LinkContext& context);
        
+                                                               // mark that target should not be unloaded unless this is also unloaded
+       void                                            addDynamicReference(const ImageLoader* target);
+                               
+                                                               // used to start iterating Segments
+       virtual SegmentIterator         beginSegments() const = 0;
+       
+                                                               // used to end iterating Segments
+       virtual SegmentIterator         endSegments() const = 0;
+       
+
        static uint32_t                         fgImagesWithUsedPrebinding;
+       static uint32_t                         fgImagesUsedFromSharedCache;
+       static uint32_t                         fgImagesRequiringNoFixups;
        static uint32_t                         fgTotalRebaseFixups;
        static uint32_t                         fgTotalBindFixups;
+       static uint32_t                         fgTotalBindSymbolsResolved;
+       static uint32_t                         fgTotalBindImageSearches;
        static uint32_t                         fgTotalLazyBindFixups;
        static uint32_t                         fgTotalPossibleLazyBindFixups;
+       static uint32_t                         fgTotalSegmentsMapped;
+       static uint64_t                         fgTotalBytesMapped;
+       static uint64_t                         fgTotalBytesPreFetched;
        static uint64_t                         fgTotalLoadLibrariesTime;
        static uint64_t                         fgTotalRebaseTime;
        static uint64_t                         fgTotalBindTime;
-       static uint64_t                         fgTotalNotifyTime;
        static uint64_t                         fgTotalInitTime;
        static uintptr_t                        fgNextSplitSegAddress;
        const char*                                     fPath;
@@ -388,31 +529,54 @@ protected:
        ino_t                                           fInode;
        time_t                                          fLastModified;
        uint64_t                                        fOffsetInFatFile;
-       std::vector<class Segment*> fSegments;
        DependentLibrary*                       fLibraries;
        uint32_t                                        fLibrariesCount;
        uint32_t                                        fPathHash;
-       uint32_t                                        fReferenceCount;
-       bool                                            fAllLibraryChecksumsAndLoadAddressesMatch;
-       bool                                            fLeaveMapped;           // when unloaded, leave image mapped in cause some other code may have pointers into it
-
+       uint32_t                                        fDlopenReferenceCount;  // count of how many dlopens have been done on this image
+       uint32_t                                        fStaticReferenceCount;  // count of images that have a fLibraries entry pointing to this image
+       uint32_t                                        fDynamicReferenceCount; // count of images that have a fDynamicReferences entry pointer to this image
+       std::set<const ImageLoader*>* fDynamicReferences;       // list of all images this image used because of a flat/coalesced lookup
 
 private:
+#if RECURSIVE_INITIALIZER_LOCK
+       struct recursive_lock {
+                                               recursive_lock(mach_port_t t) : thread(t), count(0) {}
+               mach_port_t             thread;
+               int                             count;
+       };
+       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);
-       uint64_t                                        copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize);
-       const ImageLoader::Symbol*      findExportedSymbolInDependentImagesExcept(const char* name, std::set<const ImageLoader*>& dontSearchImages, ImageLoader** foundIn) const;
-
-
-       bool                                            fHideSymbols;           // ignore this image's exported symbols when linking other images
-       bool                                            fMatchByInstallName;// look at image's install-path not its load path
-       bool                                            fLibrariesLoaded;
-       bool                                            fBased;
-       bool                                            fBoundAllNonLazy;
-       bool                                            fBoundAllLazy;
-       bool                                            fAnnounced;
-       bool                                            fInitialized;
-       uint16_t                                        fNextAddImageIndex;
+       const ImageLoader::Symbol*      findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart, 
+                                                                               const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
+
+
+
+       uint16_t                                        fDepth;
+       uint16_t                                        fLoadOrder;
+       uint32_t                                        fState : 8,
+                                                               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,
+                                                               fPathOwnedByImage : 1;
+
+#if RECURSIVE_INITIALIZER_LOCK
+       recursive_lock*                         fInitializerRecursiveLock;
+#else
+       uint32_t                                        fInitializerLock;
+#endif
+       static uint16_t                         fgLoadOrdinal;
 };
 
 
@@ -426,7 +590,6 @@ class Segment {
 public:
        virtual                                         ~Segment() {}
 
-       virtual const ImageLoader*      getImage() = 0;
        virtual const char*                     getName() = 0;
        virtual uintptr_t                       getSize() = 0;
        virtual uintptr_t                       getFileSize() = 0;
@@ -436,10 +599,14 @@ public:
        virtual bool                            writeable() = 0;
        virtual bool                            executable() = 0;
        virtual bool                            unaccessible() = 0;
-       virtual bool                            hasFixUps() = 0;
-       virtual uintptr_t                       getActualLoadAddress() = 0;
+       virtual uintptr_t                       getActualLoadAddress(const ImageLoader*) = 0;
        virtual uintptr_t                       getPreferredLoadAddress() = 0;
-       virtual void                            setUnMapWhenDestructed(bool unmap) = 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
@@ -449,21 +616,24 @@ protected:
 
        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 ImageLoader::LinkContext& context);
-       static uintptr_t                        fgNextNonSplitSegAddress;
+       static uintptr_t                        reserveAnAddressRange(size_t length, const class ImageLoader::LinkContext& context);
+       static uintptr_t                        fgNextPIEDylibAddress;
 
 private:
-       void                                            map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader::LinkContext& context);
-       void                                            map(const void* memoryImage, intptr_t slide, const ImageLoader::LinkContext& context);
-       void                                            setPermissions();
-       void                                            tempWritable();
+       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 2d2cb44fb6d7b08e41ea1c6fe71e776623a88e06..fcf7cd71167ce1e2920cc0ebab1bac42fac7be07 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @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 <sys/types.h>
+#include <sys/fcntl.h>
 #include <sys/stat.h> 
 #include <sys/mman.h>
 #include <mach/shared_memory_server.h>
@@ -35,6 +42,7 @@
 #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
        #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 "mach-o/dyld_gdb.h"
-
-// no header for this yet, rdar://problem/3850825
-extern "C" void sys_icache_invalidate(void *, size_t);
+#include "mach-o/dyld_images.h"
 
 // optimize strcmp for ppc
 #if __ppc__
@@ -59,6 +72,11 @@ extern "C" void sys_icache_invalidate(void *, size_t);
        #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
@@ -90,6 +108,9 @@ uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs = 0;
 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs = 0;
 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports = 0;
 
+#if __i386__
+uint32_t ImageLoaderMachO::fgReadOnlyImportSpinLock = 0;
+#endif
 
 //#define LINKEDIT_USAGE_DEBUG 1
 
@@ -104,8 +125,11 @@ uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports = 0;
        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);
-               fprintf(stderr, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page, dyld::findImageContainingAddress(addr)->getPath());
        }
 #endif
 
@@ -118,20 +142,79 @@ void ImageLoaderMachO::init()
        fStrings                = NULL;
        fDynamicInfo    = NULL;
        fSlide                  = 0;
-       fIsSplitSeg             = false;
-       fHasSubLibraries= false;
-       fHasSubUmbrella = false;
-       fDashInit               = NULL;
-       fModInitSection = NULL;
-       fModTermSection = NULL;
-       fDATAdyld               = NULL;
-       fImageNotifySection     = NULL;
        fTwoLevelHints  = NULL;
        fDylibID                = NULL;
-       fReExportThruFramework  = NULL;
+#if TEXT_RELOC_SUPPORT
        fTextSegmentWithFixups = NULL;
+#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;
+#endif
+}
+
+// create image for main executable
+ImageLoaderMachO::ImageLoaderMachO(const struct mach_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
+ : ImageLoader(path)
+{
+       // 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();
+
+       // 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());
+               }
+       }
 }
 
+
 // 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)
@@ -145,12 +228,68 @@ ImageLoaderMachO::ImageLoaderMachO(const char* moduleName, const struct mach_hea
        // create segments
        this->instantiateSegments((const uint8_t*)mh);
        
-       // map segments
-       if ( mh->filetype != MH_EXECUTE )
+       // map segments 
+       if ( mh->filetype == MH_EXECUTE ) {
+               throw "can't load another MH_EXECUTE";
+       }
+       else {
                ImageLoader::mapSegments((const void*)mh, len, context);
+       }
+       
+       // 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);
+               
+}
+
+// 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();
+
+       // 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());
+               }
+       }
+
        // 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);
 }
 
 
@@ -185,16 +324,62 @@ ImageLoaderMachO::ImageLoaderMachO(const char* path, int fd, const uint8_t first
        // 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);
+
 }
 
+
+
 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);
 }
 
 
@@ -204,18 +389,114 @@ void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData)
        const uint32_t cmd_count = ((macho_header*)fileData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fileData[sizeof(macho_header)];
 
-       // construct Segment object for each LC_SEGMENT cmd and add to list
+       // 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 ) {
-                       if ( (((struct macho_segment_command*)cmd)->vmsize != 0) || !fIsSplitSeg )
-                               fSegments.push_back(new SegmentMachO((struct macho_segment_command*)cmd, this, fileData));
+                       // ignore zero-sized segments
+                       if ( ((struct macho_segment_command*)cmd)->vmsize != 0 )
+                               ++segCount;
+               }
+               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);
        }
 }
 
 
+void ImageLoaderMachO::adjustSegments()
+{
+       // tell each segment where is load command is finally mapped
+       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;
+                       }
+               }
+               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);
+       }
+       
+       // 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 
 {
@@ -270,9 +551,12 @@ bool ImageLoaderMachO::needsCoalescing() const
        return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
 }
 
-#if !__LP64__   // split segs not supported for 64-bits
 
-#if 1 // hack until kernel headers and glue are in system
+
+
+
+
+// hack until kernel headers and glue are in system
 struct _shared_region_mapping_np {
     mach_vm_address_t   address;
     mach_vm_size_t      size;
@@ -285,6 +569,7 @@ struct _shared_region_range_np {
     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).
@@ -304,13 +589,13 @@ _shared_region_map_file_np(
        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
 {
-       //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
+       //dyld::log("%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
        //for ( unsigned int i=0; i < regionCount; ++i) {
-       //      fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
+       //      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)
-//             fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
+//             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.
@@ -321,21 +606,14 @@ _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
 {
-       //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges);
+       //dyld::log("%s(%u, %8p)\n", __func__, rangeCount, ranges);
        int r = syscall(300, rangeCount, ranges);
 //     if(0 != r)
-//             fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
+//             dyld::log("%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
     return r;
 }
 #define KERN_SHREG_PRIVATIZABLE        54
-#endif // hack until kernel headers and glue are in system
 
-static uintptr_t sNextAltLoadAddress 
-#if __ppc_
-       = 0xC0000000;
-#else
-       = 0;
-#endif
 
 static int 
 _shared_region_map_file_with_mmap(
@@ -359,8 +637,8 @@ _shared_region_map_file_with_mmap(
                        if ( regions[i].init_prot & VM_PROT_WRITE )
                                protection   |= PROT_WRITE;
                        off_t offset = regions[i].file_offset;
-                       //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
-                       mmapAddress = mmap(mmapAddress, size, protection, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, 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";
                }
@@ -388,6 +666,56 @@ hasSharedRegionMapFile(void)
        return 0 != value;
 }
 
+#endif // SPLIT_SEG_SHARED_REGION_SUPPORT      
+
+
+#if SPLIT_SEG_DYLIB_SUPPORT    
+unsigned int
+ImageLoaderMachO::getExtraZeroFillEntriesCount()
+{
+       // 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;
+               }
+       }
+}
+
 int
 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
                                                                                                        uint64_t offsetInFat,
@@ -395,7 +723,14 @@ ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
                                                                                                        uint64_t fileLen,
                                                                                                        const LinkContext& context)
 {
-       const unsigned int segmentCount = fSegments.size();
+       static uintptr_t sNextAltLoadAddress 
+       #if __ppc_
+               = 0xC0000000;
+       #else
+               = 0;
+       #endif
+
+       const unsigned int segmentCount = fSegmentsArrayCount;
        const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
        const unsigned int regionCount = segmentCount+extraZeroFillEntries;
        _shared_region_mapping_np regions[regionCount];
@@ -435,8 +770,8 @@ ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
                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 ) {
-                               // do nothing vm_allocate() zero-fills by default
+                       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);
@@ -449,8 +784,8 @@ ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
                                if ( regions[i].init_prot & VM_PROT_WRITE )
                                        protection   |= PROT_WRITE;
                                off_t offset = regions[i].file_offset;
-                               //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
-                               mmapAddress = mmap(mmapAddress, size, protection, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, 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";
                        }
@@ -461,19 +796,19 @@ ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
                
                // logging
                if ( context.verboseMapping ) {
-                       fprintf(stderr, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath());
+                       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 = fSegments[segIndex];
+                               Segment* seg = &fSegmentsArray[segIndex];
                                const _shared_region_mapping_np* entry = &regions[entryIndex];
                                if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1);
+                                       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;
-                                               fprintf(stderr, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1));
+                                               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;
                                        }
                                }
@@ -486,10 +821,14 @@ ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
 
 void ImageLoaderMachO::mapSegments(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 ImageLoader::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
+
+#if SPLIT_SEG_SHARED_REGION_SUPPORT    
        enum SharedRegionState
        {
                kSharedRegionStartState = 0,
-               kSharedRegionLoadFileState,
                kSharedRegionMapFileState,
                kSharedRegionMapFilePrivateState,
                kSharedRegionMapFilePrivateMMapState,
@@ -497,42 +836,27 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
        };
        static SharedRegionState sSharedRegionState = kSharedRegionStartState;
 
-       // non-split segment libraries handled by super class
-       if ( !fIsSplitSeg )
-               return ImageLoader::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
-       
        if ( kSharedRegionStartState == sSharedRegionState ) {
                if ( hasSharedRegionMapFile() ) {
-                       if ( context.slideAndPackDylibs ) { 
-                               sharedRegionMakePrivate(context);
-                               // remove underlying submap and block out 0x90000000 to 0xAFFFFFFF
-                               vm_address_t addr = (vm_address_t)0x90000000;
-                               vm_deallocate(mach_task_self(), addr, 0x20000000);
-                               vm_allocate(mach_task_self(), &addr, 0x20000000, false);
-                               sSharedRegionState = kSharedRegionMapFilePrivateMMapState;
-                       }
-                       else if ( context.sharedRegionMode == kUsePrivateSharedRegion ) { 
+                       if ( context.sharedRegionMode == kUsePrivateSharedRegion ) { 
                                sharedRegionMakePrivate(context);
                                sSharedRegionState = kSharedRegionMapFilePrivateState;
                        }
                        else if ( context.sharedRegionMode == kDontUseSharedRegion ) {
                                sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
                        }
+                       else if ( context.sharedRegionMode == kSharedRegionIsSharedCache ) {
+                               sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
+                       }
                        else {
                                sSharedRegionState = kSharedRegionMapFileState;
                        }
                }
                else {
-                       sSharedRegionState = kSharedRegionLoadFileState;
-               }
-       }
-       
-       if ( kSharedRegionLoadFileState == sSharedRegionState ) {
-               if ( 0 != sharedRegionLoadFile(fd, offsetInFat, lenInFat, fileLen, context) ) {
                        sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
                }
        }
-       else
+       
        if ( kSharedRegionMapFileState == sSharedRegionState ) {
                if ( 0 != sharedRegionMapFile(fd, offsetInFat, lenInFat, fileLen, context) ) {
                        sharedRegionMakePrivate(context);
@@ -551,77 +875,37 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
                        throw "mapping error";
                }
        }
-}
-
-unsigned int
-ImageLoaderMachO::getExtraZeroFillEntriesCount()
-{
-       // calculate mapping entries
-       const unsigned int segmentCount = fSegments.size();
-       unsigned int extraZeroFillEntries = 0;
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
-               if ( seg->hasTrailingZeroFill() )
-                       ++extraZeroFillEntries;
+#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";
        }
-       
-       return extraZeroFillEntries;
+#endif
 }
+#endif // SPLIT_SEG_DYLIB_SUPPORT
 
-void
-ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
-                                                                  _shared_region_mapping_np *mappingTable)
-{
-       unsigned int segmentCount = fSegments.size();
-       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-               Segment* seg = fSegments[segIndex];
-               _shared_region_mapping_np* entry = &mappingTable[entryIndex];
-               entry->address                  = seg->getActualLoadAddress();
-               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;
-               }
-       }
-}
-       
-int
-ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext& context)
+
+#if SPLIT_SEG_SHARED_REGION_SUPPORT    
+int ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext& context)
 {
        if ( context.verboseMapping )
-               fprintf(stderr, "dyld: making shared regions private\n");
+               dyld::log("dyld: making shared regions private\n");
 
        // shared mapping failed, so make private copy of shared region and try mapping private
-       RegionsVector allRegions;
-       context.getAllMappedRegions(allRegions);
-       std::vector<_shared_region_range_np> splitSegRegions;
-       const unsigned int allRegiontCount = allRegions.size();
-       for(unsigned int i=0; i < allRegiontCount; ++i){
-               MappedRegion region = allRegions[i];
-               uint8_t highByte = region.address >> 28;
+       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 = region.address;
-                       splitRegion.size = region.size;
-                       splitSegRegions.push_back(splitRegion);
+                       splitRegion.address = p->address;
+                       splitRegion.size = p->size;
+                       *sp++ = splitRegion;
                }
        }
-       int result = _shared_region_make_private_np(splitSegRegions.size(), &splitSegRegions[0]);
+       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;
@@ -635,7 +919,7 @@ ImageLoaderMachO::sharedRegionMapFile(int fd,
                                          const LinkContext& context)
 {
        // build table of segments to map
-       const unsigned int segmentCount = fSegments.size();
+       const unsigned int segmentCount = fSegmentsArrayCount;
        const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
        const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
        _shared_region_mapping_np mappingTable[mappingTableCount];
@@ -649,20 +933,21 @@ ImageLoaderMachO::sharedRegionMapFile(int fd,
                if(NULL != slidep && 0 != *slidep) {
                        // update with actual load addresses
                }
+               this->setNeverUnload();
                if ( context.verboseMapping ) {
-                       fprintf(stderr, "dyld: Mapping split-seg shared %s\n", this->getPath());
+                       dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
                        for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-                               Segment* seg = fSegments[segIndex];
+                               Segment* seg = &fSegmentsArray[segIndex];
                                const _shared_region_mapping_np* entry = &mappingTable[entryIndex];
                                if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1);
+                                       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;
-                                               fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1));
+                                               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;
                                        }
                                }
@@ -681,33 +966,8 @@ ImageLoaderMachO::sharedRegionMapFilePrivate(int fd,
                                                                                         const LinkContext& context,
                                                                                         bool usemmap)
 {
-       const unsigned int segmentCount = fSegments.size();
-
-       // adjust base address of segments to pack next to last dylib
-       if ( context.slideAndPackDylibs ) {
-               uintptr_t lowestReadOnly = (uintptr_t)(-1);
-               uintptr_t lowestWritable = (uintptr_t)(-1);
-               for(unsigned int segIndex=0; segIndex < segmentCount; ++segIndex){
-                       Segment* seg = fSegments[segIndex];
-                       uintptr_t segEnd = seg->getActualLoadAddress();
-                       if ( seg->writeable() ) {
-                               if ( segEnd < lowestWritable )
-                                       lowestWritable = segEnd;
-                       }
-                       else {
-                               if ( segEnd < lowestReadOnly )
-                                       lowestReadOnly = segEnd;
-                       }
-               }
-               uintptr_t baseAddress;
-               if ( lowestWritable - 256*1024*1024 < lowestReadOnly )
-                       baseAddress = lowestWritable - 256*1024*1024;
-               else
-                       baseAddress = lowestReadOnly;
-               // record that we want dylb slid to fgNextSplitSegAddress
-               this->setSlide(fgNextSplitSegAddress - baseAddress);
-       }
-       
+       const unsigned int segmentCount = fSegmentsArrayCount;
+
        // build table of segments to map
        const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
        const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
@@ -720,150 +980,50 @@ ImageLoaderMachO::sharedRegionMapFilePrivate(int fd,
        if ( usemmap )
                r = _shared_region_map_file_with_mmap(fd, mappingTableCount, mappingTable);
        else
-               r = _shared_region_map_file_np(fd, mappingTableCount, mappingTable, context.slideAndPackDylibs ? NULL : &slide);
+               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 )
-                               fprintf(stderr, "dyld: Mapping split-seg un-shared %s\n", this->getPath());
+                               dyld::log("dyld: Mapping split-seg un-shared %s\n", this->getPath());
                        else
-                               fprintf(stderr, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide, this->getPath());
+                               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 = fSegments[segIndex];
+                               Segment* seg = &fSegmentsArray[segIndex];
                                const _shared_region_mapping_np* entry = &mappingTable[entryIndex];
                                if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1);
+                                       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;
-                                               fprintf(stderr, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress() + segOffset), (uintptr_t)(seg->getActualLoadAddress() + segOffset + nextEntry->size - 1));
+                                               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 ( context.slideAndPackDylibs ) {
-                       // calculate where next split-seg dylib can load
-                       uintptr_t largestReadOnly = 0;
-                       uintptr_t largestWritable = 0;
-                       for (unsigned int segIndex=0; segIndex < segmentCount; ++segIndex) {
-                               Segment* seg = fSegments[segIndex];
-                               uintptr_t segEnd = seg->getActualLoadAddress()+seg->getSize();
-                               segEnd = (segEnd+4095) & (-4096); // page align
-                               if ( seg->writeable() ) {
-                                       if ( segEnd > largestWritable )
-                                               largestWritable = segEnd;
-                               }
-                               else {
-                                       if ( segEnd > largestReadOnly )
-                                               largestReadOnly = segEnd;
-                               }
-                       }
-                       if ( largestWritable - 256*1024*1024 > largestReadOnly )
-                               fgNextSplitSegAddress = largestWritable - 256*1024*1024;
-                       else
-                               fgNextSplitSegAddress = largestReadOnly;
-               }
        }
-       if ( context.slideAndPackDylibs && (r != 0) )
-               throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r);
+       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;
 }
 
-
-int
-ImageLoaderMachO::sharedRegionLoadFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
+void
+ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
+                                                                  sf_mapping *mappingTable,
+                                                                  uintptr_t baseAddress)
 {
-       
-       // map in split segment file at random address, then tell kernel to share it
-       void* loadAddress = 0;
-       loadAddress = mmap(NULL, fileLen, PROT_READ, MAP_FILE, fd, 0);
-       if ( loadAddress == ((void*)(-1)) )
-               throw "mmap error";
-
-       // calculate mapping entries
-       const unsigned int segmentCount = fSegments.size();
-       unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
-       
-       // build table of segments to map
-       const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
-       const uintptr_t baseAddress = fSegments[0]->getPreferredLoadAddress();
-       sf_mapping mappingTable[mappingTableCount];
-       initMappingTable(offsetInFat, mappingTable, baseAddress);
-       
-       
-       // use load_shared_file() to map all segments at once
-       int flags = 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use
-       static bool firstTime = true;
-       if ( firstTime ) {
-               // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region
-               // this is used by Xcode to prevent development libraries from polluting the global shared segment
-               if ( context.sharedRegionMode == kUsePrivateSharedRegion )
-                       flags |= NEW_LOCAL_SHARED_REGIONS;
-               firstTime = false;
-       }
-       
-       caddr_t base_address = (caddr_t)baseAddress;
-       kern_return_t r;
-       r = load_shared_file(   (char*)fPath,           // path of file to map shared
-                                                       (char*)loadAddress, // beginning of local copy of sharable pages in file
-                                                       fileLen,                        // end of shareable pages in file
-                                                       &base_address,          // beginning of address range to map
-                                                       mappingTableCount,  // number of entres in array of sf_mapping
-                                                       mappingTable,           // the array of sf_mapping
-                                                       &flags);                        // in/out flags
-       if ( 0 != r ) {
-               // try again but tell kernel it is ok to slide
-               flags |= ALTERNATE_LOAD_SITE;
-               r = load_shared_file((char*)fPath,(char*)loadAddress, fileLen, &base_address,   
-                                                       mappingTableCount, mappingTable, &flags);
-       }
-       
-       // unmap file from random address now that they are (hopefully) mapped into the shared region
-       munmap(loadAddress, fileLen);
-
-       if ( 0 == r ) {
-               if ( base_address != (caddr_t)baseAddress )
-                       this->setSlide((uintptr_t)base_address - baseAddress);
-               if ( context.verboseMapping ) {
-                       if ( base_address != (caddr_t)baseAddress )
-                               fprintf(stderr, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath());
-                       else
-                               fprintf(stderr, "dyld: Mapping split-seg load_shared %s\n", this->getPath());
-                       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-                               Segment* seg = fSegments[segIndex];
-                               const sf_mapping* entry = &mappingTable[entryIndex];
-                               if ( (entry->protection & VM_PROT_ZF) == 0 )
-                                       fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(), seg->getActualLoadAddress()+seg->getFileSize()-1);
-                               if ( entryIndex < (mappingTableCount-1) ) {
-                                       const sf_mapping* nextEntry = &mappingTable[entryIndex+1];
-                                       if ( (nextEntry->protection & VM_PROT_ZF) != 0 ) {
-                                               fprintf(stderr, "%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), (uintptr_t)(nextEntry->mapping_offset + base_address), (uintptr_t)(nextEntry->mapping_offset + base_address + nextEntry->size - 1));
-                                               ++entryIndex;
-                                       }
-                               }
-                       }
-               }
-       }
-       return r;
-}
-void
-ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
-                                                                  sf_mapping *mappingTable,
-                                                                  uintptr_t baseAddress)
-{
-       unsigned int segmentCount = fSegments.size();
+       unsigned int segmentCount = fSegmentsArrayCount;
        for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-               Segment* seg = fSegments[segIndex];
+               Segment* seg = &fSegmentsArray[segIndex];
                sf_mapping* entry = &mappingTable[entryIndex];
                entry->mapping_offset   = seg->getPreferredLoadAddress() - baseAddress;
                entry->size                             = seg->getFileSize();
@@ -890,7 +1050,8 @@ ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
        }
 }
 
-#endif //  !__LP64__  split segs not supported for 64-bits
+#endif // SPLIT_SEG_SHARED_REGION_SUPPORT      
+
 
 
 void ImageLoaderMachO::setSlide(intptr_t slide)
@@ -901,27 +1062,42 @@ void ImageLoaderMachO::setSlide(intptr_t slide)
 void ImageLoaderMachO::parseLoadCmds()
 {
        // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i){
-               Segment* seg = fSegments[i];
+       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() - seg->getFileOffset());
+                       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 ( seg->hasFixUps() )
+                       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());
+                       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;
 
+       // keep count of images used in shared cache
+       if ( fInSharedCache )
+               ++fgImagesUsedFromSharedCache;
+
        // 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)];
@@ -942,34 +1118,34 @@ void ImageLoaderMachO::parseLoadCmds()
                                fHasSubUmbrella = true;
                                break;
                        case LC_SUB_FRAMEWORK:
-                               {
-                                       const struct sub_framework_command* subf = (struct sub_framework_command*)cmd;
-                                       fReExportThruFramework = (char*)cmd + subf->umbrella.offset;
-                               }
+                               fInUmbrella = true;
                                break;
                        case LC_SUB_LIBRARY:
                                fHasSubLibraries = true;
                                break;
                        case LC_ROUTINES_COMMAND:
-                               fDashInit = (struct macho_routines_command*)cmd;
+                               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 )
-                                                       fModInitSection = sect;
+                                                       fHasInitializers = true;
                                                else if ( type == S_MOD_TERM_FUNC_POINTERS )
-                                                       fModTermSection = sect;
-                                               else if ( isDataSeg && (strcmp(sect->sectname, "__dyld") == 0) ) {
-                                                               fDATAdyld = sect;
-                                               }
+                                                       fHasTerminators = true;
+                                               else if ( type == S_DTRACE_DOF )
+                                                       fHasDOFSections = true;
+#if IMAGE_NOTIFY_SUPPORT
                                                else if ( isDataSeg && (strcmp(sect->sectname, "__image_notify") == 0) )
-                                                       fImageNotifySection = sect;
+                                                       fHasImageNotifySection = true;
+#endif
                                        }
                                }
                                break;
@@ -981,12 +1157,14 @@ void ImageLoaderMachO::parseLoadCmds()
                                        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 )
-                                       throwf("unknown required load command 0x%08X", cmd->cmd);
+                                       dyld::throwf("unknown required load command 0x%08X", cmd->cmd);
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
@@ -1006,23 +1184,33 @@ const char* ImageLoaderMachO::getInstallPath() const
 // 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 ( fReExportThruFramework != NULL ) {
-               // 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], fReExportThruFramework) == 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(fReExportThruFramework)+1];
-                                       strcpy(reexportAndSuffix, fReExportThruFramework);
-                                       strcat(reexportAndSuffix, context.imageSuffix);
-                                       if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
-                                               return true;
+       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;
@@ -1109,7 +1297,8 @@ bool ImageLoaderMachO::hasSubLibrary(const LinkContext& context, const ImageLoad
        return false;
 }
 
-       
+
+
 void* ImageLoaderMachO::getMain() const
 {
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
@@ -1121,16 +1310,16 @@ void* ImageLoaderMachO::getMain() const
                        {
                        #if __ppc__
                                const ppc_thread_state_t* registers = (ppc_thread_state_t*)(((char*)cmd) + 16);
-                               return (void*)registers->srr0;
+                               return (void*)(registers->srr0 + fSlide);
                        #elif __ppc64__
                                const ppc_thread_state64_t* registers = (ppc_thread_state64_t*)(((char*)cmd) + 16);
-                               return (void*)registers->srr0;
+                               return (void*)(registers->srr0 + fSlide);
                        #elif __i386__
                                const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
-                               return (void*)registers->eip;
+                               return (void*)(registers->eip + fSlide);
                        #elif __x86_64__
                                const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
-                               return (void*)registers->rip;
+                               return (void*)(registers->rip + fSlide);
                        #else
                                #warning need processor specific code
                        #endif
@@ -1153,6 +1342,7 @@ uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
                switch (cmd->cmd) {
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
                                ++count;
                                break;
                }
@@ -1161,7 +1351,7 @@ uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
        return count;
 }
 
-void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs[])
+void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
 {
        uint32_t index = 0;
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
@@ -1171,18 +1361,17 @@ void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs[])
                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;
-                               DependentLibrary* lib = &libs[index++];
+                               DependentLibraryInfo* lib = &libs[index++];
                                lib->name = (char*)cmd + dylib->dylib.name.offset;
                                //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
-                               lib->image = NULL;
                                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_DYLIB);
-                               lib->checksumMatches = false;
-                               lib->isReExported = false;
+                               lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
+                               lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
                        }
                        break;
                }
@@ -1206,34 +1395,95 @@ ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo()
        return info;
 }
 
+void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const char*>& paths) 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) {
+               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());
+                                               break;
+                                       }
+                                       char resolvedPath[PATH_MAX];
+                                       if ( realpath(this->getPath(), resolvedPath) != NULL ) {
+                                               char newRealPath[strlen(resolvedPath) + strlen(path)];
+                                               strcpy(newRealPath, resolvedPath);
+                                               char* addPoint = strrchr(newRealPath,'/');
+                                               if ( addPoint != NULL )
+                                                       strcpy(&addPoint[1], &path[13]);
+                                               else
+                                                       strcpy(newRealPath, &path[13]);
+                                               path = strdup(newRealPath);
+                                       }
+                               }
+                               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());
+                                               break;
+                                       }
+                                       char resolvedPath[PATH_MAX];
+                                       if ( realpath(context.mainExecutable->getPath(), resolvedPath) != NULL ) {
+                                               char newRealPath[strlen(resolvedPath) + strlen(path)];
+                                               strcpy(newRealPath, resolvedPath);
+                                               char* addPoint = strrchr(newRealPath,'/');
+                                               if ( addPoint != NULL )
+                                                       strcpy(&addPoint[1], &path[17]);
+                                               else
+                                                       strcpy(newRealPath, &path[17]);
+                                               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());
+                                       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 (std::vector<class Segment*>::iterator it=fSegments.begin(); it != fSegments.end(); ++it) {
-               if ( (*it)->writeable() ) {
-                       return (*it)->getActualLoadAddress();
-               }
+       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()
 {
-#if __x86_64__
-       // r_address is offset from first writable segment
-       return getFirstWritableSegmentAddress();
-#endif
+       // r_address is either an offset from the first segment address
+       // or from the first writable segment address
 #if __ppc__ || __i386__
-       if ( fIsSplitSeg ) {
-               // in split segment libraries r_address is offset from first writable segment
+       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
-       
-       // in non-split segment libraries r_address is offset from first segment
-       return fSegments[0]->getActualLoadAddress();
 }
 
+
 #if __ppc__
 static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationType, uint16_t otherHalf, uintptr_t slide)
 {
@@ -1257,7 +1507,7 @@ static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationTy
                        instruction->immediateValue = temp >> 16;
        }
        //uint32_t after = *((uint32_t*)locationToFix);
-       //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
+       //dyld::log("dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
 }
 #endif
 
@@ -1295,34 +1545,27 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
 {
        // if prebound and loaded at prebound address, then no need to rebase
        if ( this->usablePrebinding(context) ) {
-               // skip rebasing cause prebound and prebinding not disabled
+               // skip rebasing because prebinding is valid
                ++fgImagesWithUsedPrebinding; // bump totals for statistics
                return;
        }
        
-       // <rdar://problem/5146059> update_prebinding fails if a prebound dylib depends on a non-prebound dylib
-       // In the unusual case that we find a prebound dylib dependent on un-prebound dylib and we are running
-       // update_prebinding, we want the link of the prebound dylib to fail so that it will be excluded from 
-       // the list of dylibs to be re-written.
-       if ( context.prebinding && !this->isPrebindable() )
-               throwf("dylib not prebound: %s", this->getPath());
-       
        // print why prebinding was not used
        if ( context.verbosePrebinding ) {
                if ( !this->isPrebindable() ) {
-                       fprintf(stderr, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
+                       dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
                }
                else if ( fSlide != 0 ) {
-                       fprintf(stderr, "dyld: image slid, so could not use prebinding in %s\n", this->getPath());
+                       dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
                }
                else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
-                       fprintf(stderr, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
+                       dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
                }
                else if ( !this->usesTwoLevelNameSpace() ){
-                       fprintf(stderr, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
+                       dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
                }
                else {
-                       fprintf(stderr, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
+                       dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
                }
        }
 
@@ -1330,24 +1573,35 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
        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 and we got here, then prebinding is not valid, so reset all lazy pointers
-       if ( this->isPrebindable() )
+       // 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);
 #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 ) 
                return;
 
+#if TEXT_RELOC_SUPPORT
        // if there are __TEXT fixups, temporarily make __TEXT writable
        if ( fTextSegmentWithFixups != NULL ) 
-               fTextSegmentWithFixups->tempWritable();
-
+               fTextSegmentWithFixups->tempWritable(context, this);
+#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 ) 
@@ -1359,8 +1613,7 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
                if ( reloc->r_extern != 0 ) 
                        throw "extern relocation found with local relocations";
                *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
-       #endif
-       #if __ppc__ || __ppc64__ || __i386__
+       #else   
                if ( (reloc->r_address & R_SCATTERED) == 0 ) {
                        if ( reloc->r_symbolnum == R_ABS ) {
                                // ignore absolute relocations
@@ -1403,15 +1656,14 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
                                                ++reloc; // these relocations come in pairs, get next one
                                                otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide);
                                                break;
-               #endif
-               #if __ppc__ 
                                        case PPC_RELOC_PB_LA_PTR:
                                                // do nothing
                                                break;
                #elif __ppc64__
                                        case PPC_RELOC_PB_LA_PTR:
-                                               // these should never exist in ppc64, but the first ld64 had a bug and created them
-                                               *locationToFix = sreloc->r_value + slide;
+                                               // 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:
@@ -1426,22 +1678,23 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
                                throw "bad local scattered relocation length";
                        }
                }
-       #endif
+       #endif // x86_64
        }
        
+#if TEXT_RELOC_SUPPORT
        // if there were __TEXT fixups, restore write protection
        if ( fTextSegmentWithFixups != NULL ) {
-               fTextSegmentWithFixups->setPermissions();
-               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(), fTextSegmentWithFixups->getSize());
+               fTextSegmentWithFixups->setPermissions(context,this);
+               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(this), fTextSegmentWithFixups->getSize());
        }
-       
+#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 struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
 {
        int32_t high = symbolCount-1;
        int32_t mid = hintIndex;
@@ -1454,6 +1707,9 @@ const struct macho_nlist* ImageLoaderMachO::binarySearchWithToc(const char* key,
        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;
@@ -1479,9 +1735,15 @@ const struct macho_nlist* ImageLoaderMachO::binarySearchWithToc(const char* key,
        return NULL;
 }
 
-const struct macho_nlist* ImageLoaderMachO::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount)
+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];
@@ -1507,7 +1769,7 @@ const struct macho_nlist* ImageLoaderMachO::binarySearch(const char* key, const
        return NULL;
 }
 
-const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const
+const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) const
 {
        const struct macho_nlist* sym = NULL;
        const struct twolevel_hint* theHint = (struct twolevel_hint*)hint;
@@ -1596,15 +1858,22 @@ const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name
                }
        }
 
-    
+
        return NULL;
 }
 
 
-uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym) const
+
+
+uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor) const
 {
-       const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym;
-       return nlistSym->n_value + fSlide;
+       return this->getSymbolAddress((const struct macho_nlist*)sym, requestor, context);
+}
+
+uintptr_t ImageLoaderMachO::getSymbolAddress(const struct macho_nlist* sym, const ImageLoader* requestor, const LinkContext& context) const
+{
+       uintptr_t result = sym->n_value + fSlide;
+       return result;
 }
 
 ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const
@@ -1751,33 +2020,38 @@ bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist* symbol
 
 static void __attribute__((noreturn)) throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn)
 {
-       const char* formatString = "Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n";
-       char buf[strlen(symbol)+strlen(referencedFrom)+strlen(expectedIn)+strlen(formatString)];
-       sprintf(buf, formatString, symbol, referencedFrom, expectedIn);
-       throw strdup(buf);  // this is a leak if exception doesn't halt program
+       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, ImageLoader** foundIn)
+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 = undefinedSymbol->n_value + this->fSlide;
+                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, this, context);
                        *foundIn = this;
                        return addr;
                }
                const Symbol* sym;
-               if ( context.flatExportFinder(symbolName, &sym, foundIn) )
-                       return (*foundIn)->getExportedSymbolAddress(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);
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                }
                if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
                        // definition can't be found anywhere
@@ -1787,15 +2061,26 @@ uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const s
                throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
        }
        else {
-               // symbol requires searching images with coalesced symbols
+               // 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) )
-                               return (*foundIn)->getExportedSymbolAddress(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");
-                       //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
+                       //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;
@@ -1811,13 +2096,13 @@ uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const s
                        // flat lookup
                        const Symbol* sym;
                        if ( context.flatExportFinder(symbolName, &sym, foundIn) )
-                               return (*foundIn)->getExportedSymbolAddress(sym);
+                               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);
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        
                        throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup");
                }
@@ -1830,11 +2115,12 @@ uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const s
                        }
                }
                else {
-                       throw "corrupt binary, library ordinal too big";
+                       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 ) {
-                       //fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath());
+                       //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
                        throw "symbol not found";
                }
                
@@ -1851,12 +2137,12 @@ uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const s
                
                const Symbol* sym = target->findExportedSymbol(symbolName, hint, true, foundIn);
                if ( sym!= NULL ) {
-                       return (*foundIn)->getExportedSymbolAddress(sym);
+                       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 undefinedSymbol->n_value + fSlide;
+                       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
@@ -1902,14 +2188,15 @@ void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, boo
        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();
-
+               fTextSegmentWithFixups->tempWritable(context, this);
+#endif
        // cache last lookup
-       const struct macho_nlist*       lastUndefinedSymbol = 0;
+       const struct macho_nlist*       lastUndefinedSymbol = NULL;
        uintptr_t                                       symbolAddr = 0;
-       ImageLoader*                            image = NULL;
+       const ImageLoader*                      image = NULL;
        
        // loop through all external relocation records and bind each
        const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
@@ -1925,6 +2212,7 @@ void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, boo
                                                        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;
@@ -1955,21 +2243,25 @@ void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, boo
                                                if ( undefinedSymbol != lastUndefinedSymbol ) {
                                                        symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, &image);
                                                        lastUndefinedSymbol = undefinedSymbol;
+                                                       symbolAddrCached = false;
                                                }
                                                if ( context.verboseBind ) {
                                                        const char *path = NULL;
-                                                       if(NULL != image) {
+                                                       if ( image != NULL ) {
                                                                path = image->getShortName();
                                                        }
-                                                       if(0 == value) {
-                                                               fprintf(stderr, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n",
+                                                       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);
+                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
                                                        }
                                                        else {
-                                                               fprintf(stderr, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n",
+                                                               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, value);
+                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
                                                        }
                                                }
                                                value += symbolAddr;
@@ -1987,6 +2279,8 @@ void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, boo
                                                if ( !prebound || (*location != value) )
                                                        *location = value; 
                                        #endif
+                                               // update stats
+                                               ++fgTotalBindFixups;
                                        }
                                        break;
                                default:
@@ -1998,14 +2292,13 @@ void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, boo
                }
        }
        
+#if TEXT_RELOC_SUPPORT
        // if there were __TEXT fixups, restore write protection
        if ( fTextSegmentWithFixups != NULL ) {
-               fTextSegmentWithFixups->setPermissions();
-               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(), fTextSegmentWithFixups->getSize());
+               fTextSegmentWithFixups->setPermissions(context, this);
+               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(this), fTextSegmentWithFixups->getSize());
        }
-       
-       // update stats
-       fgTotalBindFixups += fDynamicInfo->nextrel;
+#endif
 }
 
 const mach_header* ImageLoaderMachO::machHeader() const
@@ -2019,19 +2312,25 @@ uintptr_t ImageLoaderMachO::getSlide() const
 }
 
 // hmm. maybe this should be up in ImageLoader??
-const void* ImageLoaderMachO::getBaseAddress() const
+const void* ImageLoaderMachO::getEnd() const
 {
-       Segment* seg = fSegments[0];
-       return (const void*)seg->getActualLoadAddress();
+       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, ImageLoader* targetImage, const LinkContext& context)
+uintptr_t ImageLoaderMachO::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();
-               fprintf(stderr, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
+               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);
        }
@@ -2125,10 +2424,16 @@ uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer, const LinkC
                                        #endif
                                                if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
                                                        const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
-                                                       ImageLoader* image = NULL;
-                                                       uintptr_t symbolAddr = this->resolveUndefined(context,  &fSymbolTable[symbolIndex], twoLevel, &image);
+                                                       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;
                                                }
                                        }
@@ -2137,14 +2442,57 @@ uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer, const LinkC
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       throw "lazy pointer not found";
+       dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
 }
 
 
+#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.linkingMainExecutable ) {
+                               _spin_lock(&fgReadOnlyImportSpinLock);
+                               context.makeSharedCacheImportSegmentsWritable(true);
+                       }
+               }
+               else {
+                       _spin_lock(&fgReadOnlyImportSpinLock);
+                       fReadOnlyImportSegment->tempWritable(context, this);
+               }
+       }
+}
 
+void ImageLoaderMachO::makeImportSegmentReadOnly(const LinkContext& context)
+{
+       if ( fReadOnlyImportSegment != NULL ) {
+               if ( fInSharedCache ) {
+                       if ( !context.linkingMainExecutable ) {
+                               context.makeSharedCacheImportSegmentsWritable(false);
+                               _spin_unlock(&fgReadOnlyImportSpinLock);
+                       }
+               }
+               else {
+                       fReadOnlyImportSegment->setPermissions(context, this);
+                       _spin_unlock(&fgReadOnlyImportSpinLock);
+               }
+       }
+}
+#endif
 
-void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context, BindingLaziness bindness, bool onlyCoalescedSymbols)
+void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys, bool onlyCoalescedSymbols)
 {
+#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;
@@ -2163,13 +2511,13 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                uint32_t elementSize = sizeof(uintptr_t);
                                                uint32_t elementCount = sect->size / elementSize;
                                                if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
-                                                       if ( (bindness == kLazyOnly) || (bindness == kLazyOnlyNoDependents) )
+                                                       if ( ! bindNonLazys )
                                                                continue;
                                                }
                                                else if ( type == S_LAZY_SYMBOL_POINTERS ) {
                                                        // process each symbol pointer in this section
                                                        fgTotalPossibleLazyBindFixups += elementCount;
-                                                       if ( bindness == kNonLazyOnly )
+                                                       if ( ! bindLazys )
                                                                continue;
                                                }
                                #if __i386__
@@ -2178,7 +2526,7 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                        elementCount = sect->size / 5;
                                                        elementSize = 5;
                                                        fgTotalPossibleLazyBindFixups += elementCount;
-                                                       if ( bindness == kNonLazyOnly )
+                                                       if ( ! bindLazys )
                                                                continue;
                                                }
                                #endif
@@ -2188,6 +2536,9 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                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;
@@ -2214,7 +2565,7 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                                                        // symbol table entry is an import entry (usually it is a local symbol
                                                                                        // definition).
                                                                                        if ( context.verboseWarnings && !alreadyWarned ) {
-                                                                                               fprintf(stderr, "dyld: malformed executable '%s', skipping indirect symbol to %s\n",
+                                                                                               dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
                                                                                                                this->getPath(), &fStrings[sym->n_un.n_strx]);
                                                                                                alreadyWarned = true;
                                                                                        }
@@ -2222,7 +2573,7 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                                                }
                                                                        }
                                                                }
-                                                               ImageLoader *image = NULL;
+                                                               const ImageLoader* image = NULL;
                                                                // if only processing coalesced symbols and this one does not require coalesceing, skip to next
                                                                if ( onlyCoalescedSymbols && !symbolRequiresCoalescing(sym) )
                                                                        continue;
@@ -2231,43 +2582,35 @@ void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context,
                                                                        
                                                                // update pointer
                                                                symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image,  context);
+                                                               // update stats
+                                                               ++fgTotalBindFixups;
                                                        }
                                                }
-                                               // update stats
-                                               fgTotalBindFixups += elementCount;
                                        }
                                }
                                break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
+#if __i386__
+       this->makeImportSegmentReadOnly(context);
+#endif
 }
 
-/*
- * The address of these symbols are written in to the (__DATA,__dyld) section
- * at the following offsets:
- *     at offset 0     stub_binding_helper_interface
- *     at offset 4     _dyld_func_lookup
- *     at offset 8     start_debug_thread
- * The 'C' types (if any) for these symbols are ignored here and all are
- * declared as longs so the assignment of their address in to the section will
- * not require a cast.  stub_binding_helper_interface is really a label in the
- * assembly code interface for the stub binding.  It does not have a meaningful 
- * 'C' type.  _dyld_func_lookup is the routine in dyld_libfuncs.c.
- * start_debug_thread is the routine in debug.c.
- *
- * For ppc the image's stub_binding_binding_helper is read from:
- *     at offset 20    the image's stub_binding_binding_helper address
- * and saved into to the image structure.
- */
+#if SUPPORT_OLD_CRT_INITIALIZATION
+// first 16 bytes of "start" in crt1.o
+#if __ppc__
+       static uint32_t sStandardEntryPointInstructions[4] = { 0x7c3a0b78, 0x3821fffc, 0x54210034, 0x38000000 };
+#elif __i386__
+       static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
+#endif
+#endif
+
 struct DATAdyld {
-       void*   dyldLazyBinder;         // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
-       void*   dyldFuncLookup;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
-       void*   startDebugThread;   // debugger interface ???
-       void*   debugPort;                      // debugger interface ???
-       void*   debugThread;            // debugger interface ???
-       void*   stubBindHelper;         // filled in at static link time to point to stub helper in image
-       void*   coreDebug;                      // ???
+       void*                   dyldLazyBinder;         // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
+       void*                   dyldFuncLookup;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
+       // the following only exist in main executables built for 10.5 or later
+       ProgramVars             vars;
 };
 
 // These are defined in dyldStartup.s
@@ -2278,29 +2621,68 @@ extern "C" void fast_stub_binding_helper_interface();
 
 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
 {
-       if ( fDATAdyld != NULL ) {
-               struct DATAdyld* dd = (struct DATAdyld*)(fDATAdyld->addr + fSlide);
-               if ( fDATAdyld->size > offsetof(DATAdyld, dyldLazyBinder) ) {
-                       if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
-                               dd->dyldLazyBinder = (void*)&stub_binding_helper;
-               }
-               if ( fDATAdyld->size > offsetof(DATAdyld, dyldFuncLookup) ) {
-                       if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup )
-                               dd->dyldFuncLookup = (void*)&dyld_func_lookup;
-               }
-               //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) ) 
-               //      dd->startDebugThread = &start_debug_thread;
-#ifdef __ppc__
-               //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) )
-               //      save = dd->stubBindHelper;      
-#endif
+       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;
+       // set up __dyld section
+       // optimizations:
+       //   1) do nothing if image is in dyld shared cache and dyld loaded at same address as when cache built
+       //       2) first read __dyld value, if already correct don't write, this prevents dirtying a page
+       if ( !fInSharedCache || !context.dyldLoadedAtSameAddressNeededBySharedCache ) {
+               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 ( 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, "__dyld" ) == 0 ) {
+                                                       struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide);
+                                                       if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) {
+                                                               if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
+                                                                       dd->dyldLazyBinder = (void*)&stub_binding_helper;
+                                                       }
+                                                       if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) {
+                                                               if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup )
+                                                                       dd->dyldFuncLookup = (void*)&dyld_func_lookup;
+                                                       }
+                                                       if ( mh->filetype == MH_EXECUTE ) {
+                                                               // there are two ways to get the program variables
+                                                               if ( (sect->size > offsetof(DATAdyld, vars)) && (dd->vars.mh == mh) ) {
+                                                                       // some really old binaries have space for vars, but it is zero filled
+                                                                       // main executable has 10.5 style __dyld section that has program variable pointers
+                                                                       context.setNewProgramVars(dd->vars);
+                                                               }
+                                                               else {
+                                                                       // main executable is pre-10.5 and requires the symbols names to be looked up
+                                                                       this->lookupProgramVars(context);
+                               #if SUPPORT_OLD_CRT_INITIALIZATION
+                                                                       // If the first 16 bytes of the entry point's instructions do not 
+                                                                       // match what crt1.o supplies, then the program has a custom entry point.
+                                                                       // This means it might be doing something that needs to be executed before 
+                                                                       // initializers are run. 
+                                                                       if ( memcmp(this->getMain(), sStandardEntryPointInstructions, 16) != 0 ) {
+                                                                               if ( context.verboseInit )
+                                                                                       dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
+                                                                               context.setRunInitialzersOldWay();
+                                                                       }
+                               #endif
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
        }
 #if __i386__
-       if ( ! this->usablePrebinding(context) || !this->usesTwoLevelNameSpace() ) {
+       if ( ! this->usablePrebinding(context) ) {
                // reset all "fast" stubs
-               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;
+               this->makeImportSegmentWritable(context);
+               cmd = cmds;
                for (uint32_t i = 0; i < cmd_count; ++i) {
                        switch (cmd->cmd) {
                                case LC_SEGMENT_COMMAND:
@@ -2328,7 +2710,7 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
                                                                        // 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];
-                                                                               ImageLoader* image = NULL;
+                                                                               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);
@@ -2362,16 +2744,50 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
                        }
                        cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                }
+               this->makeImportSegmentReadOnly(context);
        }
 #endif
 }
 
+                                                                       
+void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
+{
+       ProgramVars vars = context.programVars;
+       const ImageLoader::Symbol* sym;
+       
+       // get mach header directly
+       vars.mh = (macho_header*)fMachOData;
+       
+       // lookup _NXArgc
+       sym = this->findExportedSymbol("_NXArgc", NULL, false, NULL);
+       if ( sym != NULL )
+               vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this);
+               
+       // lookup _NXArgv
+       sym = this->findExportedSymbol("_NXArgv", NULL, false, NULL);
+       if ( sym != NULL )
+               vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
+               
+       // lookup _environ
+       sym = this->findExportedSymbol("_environ", NULL, false, NULL);
+       if ( sym != NULL )
+               vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
+               
+       // lookup __progname
+       sym = this->findExportedSymbol("___progname", NULL, false, NULL);
+       if ( sym != NULL )
+               vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this);
+               
+       context.setNewProgramVars(vars);
+}
+
+
 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
 {
        // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
-       if ( this->isPrebindable() 
+       if ( (this->isPrebindable() || fInSharedCache)
                && (this->getSlide() == 0) 
-               && (this->usesTwoLevelNameSpace() || context.prebinding)
+               && this->usesTwoLevelNameSpace()
                && this->allDependentLibrariesAsWhenPreBound() ) {
                // allow environment variables to disable prebinding
                if ( context.bindFlat )
@@ -2390,65 +2806,136 @@ bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
        return false;
 }
 
-void ImageLoaderMachO::doBind(const LinkContext& context, BindingLaziness bindness)
+void ImageLoaderMachO::doBind(const LinkContext& context, bool forceLazysBound)
 {
+       // check for runtime forcing of lazy pointers to be bound
+       if ( forceLazysBound && (this->getState() > dyld_image_state_bound) ) {
+               this->doBindIndirectSymbolPointers(context, false, forceLazysBound, false);
+               return;
+       }
+
        // 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 be imports rebound (even if correctly prebound)
-       if ( this->usablePrebinding(context) && this->usesTwoLevelNameSpace() ) {
+       // 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, kLazyAndNonLazy, 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
-       switch (bindness) {
-               case kNonLazyOnly:
-               case kLazyAndNonLazy:
-                       // external relocations are used for data initialized to external symbols
-                       this->doBindExternalRelocations(context, false);
-                       break;
-               case kLazyOnly:
-               case kLazyOnlyNoDependents:
-                       break;
-       }
-       // "indirect symbols" are used for code references to external symbols
-       this->doBindIndirectSymbolPointers(context, bindness, false);
+       // 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)
 {
-       if ( fDashInit != NULL ) {
-               Initializer func = (Initializer)(fDashInit->init_address + fSlide);
-               if ( context.verboseInit )
-                       fprintf(stderr, "dyld: calling -init function 0x%p in %s\n", func, this->getPath());
-               func(context.argc, context.argv, context.envp, context.apple);
+       if ( fHasDashInit ) {
+               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_ROUTINES_COMMAND:
+                                       Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
+                                       if ( context.verboseInit )
+                                               dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
+                                       func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+                                       break;
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
        }
 }
 
 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
 {
-       if ( fModInitSection != NULL ) {
-               Initializer* inits = (Initializer*)(fModInitSection->addr + fSlide);
-               const uint32_t count = fModInitSection->size / sizeof(uintptr_t);
-               for (uint32_t i=0; i < count; ++i) {
-                       Initializer func = inits[i];
-                       if ( context.verboseInit )
-                               fprintf(stderr, "dyld: calling initializer function %p in %s\n", func, this->getPath());
-                       func(context.argc, context.argv, context.envp, context.apple);
+       if ( fHasInitializers ) {
+               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;
+                               const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                               const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                               for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                       const uint8_t type = sect->flags & SECTION_TYPE;
+                                       if ( type == S_MOD_INIT_FUNC_POINTERS ) {
+                                               Initializer* inits = (Initializer*)(sect->addr + fSlide);
+                                               const uint32_t count = sect->size / sizeof(uintptr_t);
+                                               for (uint32_t i=0; i < count; ++i) {
+                                                       Initializer func = inits[i];
+                                                       if ( context.verboseInit )
+                                                               dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
+                                                       func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+                                               }
+                                       }
+                               }
+                               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+                       }
                }
        }
 }
 
 
+
+
+void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs)
+{
+       if ( fHasDOFSections ) {
+               // 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_SEGMENT_COMMAND:
+                                       {
+                                               const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                                               const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                                               const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                                               for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                                       if ( (sect->flags & SECTION_TYPE) == S_DTRACE_DOF ) {
+                                                               ImageLoader::DOFInfo info;
+                                                               info.dof                        = (void*)(sect->addr + fSlide);
+                                                               info.imageHeader        = this->machHeader();
+                                                               info.imageShortName = this->getShortName();
+                                                               dofs.push_back(info);
+                                                       }
+                                               }
+                                       }
+                                       break;
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
+       }
+}      
+
+
 void ImageLoaderMachO::doInitialization(const LinkContext& context)
 {
        // mach-o has -init and static initializers
@@ -2458,411 +2945,213 @@ void ImageLoaderMachO::doInitialization(const LinkContext& context)
 
 bool ImageLoaderMachO::needsInitialization()
 {
-       return ( (fDashInit != NULL) || (fModInitSection != NULL) );
+       return ( fHasDashInit || fHasInitializers );
 }
 
 
 bool ImageLoaderMachO::needsTermination()
 {
-       return ( fModTermSection != NULL );
+       return fHasTerminators;
 }
 
+#if IMAGE_NOTIFY_SUPPORT
 bool ImageLoaderMachO::hasImageNotification()
 {
-       return ( fImageNotifySection != NULL );
+       return fHasImageNotifySection;
 }
-
+#endif
 
 void ImageLoaderMachO::doTermination(const LinkContext& context)
 {
-       if ( fModTermSection != NULL ) {
-               Terminator* terms = (Terminator*)(fModTermSection->addr + fSlide);
-               const uint32_t count = fModTermSection->size / sizeof(uintptr_t);
-               for (uint32_t i=count; i > 0; --i) {
-                       Terminator func = terms[i-1];
-                       if ( context.verboseInit )
-                               fprintf(stderr, "dyld: calling terminaton function %p in %s\n", func, this->getPath());
-                       func();
+       if ( fHasTerminators ) {
+               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;
+                               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_TERM_FUNC_POINTERS ) {
+                                               Terminator* terms = (Terminator*)(sect->addr + fSlide);
+                                               const uint32_t count = sect->size / sizeof(uintptr_t);
+                                               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());
+                                                       func();
+                                               }
+                                       }
+                               }
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                }
        }
 }
 
+#if IMAGE_NOTIFY_SUPPORT
 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[])
 {
-       if ( fImageNotifySection != NULL ) {
-               dyld_image_notifier* notes = (dyld_image_notifier*)(fImageNotifySection->addr + fSlide);
-               const uint32_t count = fImageNotifySection->size / sizeof(uintptr_t);
-               for (uint32_t i=count; i > 0; --i) {
-                       dyld_image_notifier func = notes[i-1];
-                       func(mode, infoCount, 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);
-       fprintf(stderr, "total hinted binary tree searches:    %d\n", fgHintedBinaryTreeSearchs);
-       fprintf(stderr, "total unhinted binary tree searches:  %d\n", fgUnhintedBinaryTreeSearchs);
-       fprintf(stderr, "total images with weak exports:  %d\n", fgCountOfImagesWithWeakExports);
+       //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
-       fprintf(stderr, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets.size());
+       dyld::log("linkedit pages accessed (%lu):\n", sLinkEditPageBuckets.size());
 #endif 
 }
 
-void ImageLoaderMachO::doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind)
-{
-       // update __DATA segment
-       this->applyPrebindingToDATA(fileToPrebind);
-       
-       // update load commands 
-       this->applyPrebindingToLoadCommands(context, fileToPrebind, timestamp);
-       
-       // update symbol table  
-       this->applyPrebindingToLinkEdit(context, fileToPrebind);
-}
 
-void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind)
+ImageLoader::SegmentIterator   ImageLoaderMachO::beginSegments() const
 {
-       const unsigned int segmentCount = fSegments.size();
-       for(unsigned int i=0; i < segmentCount; ++i) {
-               SegmentMachO* seg = (SegmentMachO*)fSegments[i];
-               if ( seg->writeable() ) {
-                       memcpy(&fileToPrebind[seg->fFileOffset], (void*)seg->getActualLoadAddress(), seg->fFileSize);
-               }
-       }
+       return SegmentIterator(fSegmentsArray);
 }
 
-void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext& context, uint8_t* fileToPrebind, time_t timestamp)
+ImageLoader::SegmentIterator   ImageLoaderMachO::endSegments() const
 {
-       macho_header* mh = (macho_header*)fileToPrebind;
-       const uint32_t cmd_count = mh->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fileToPrebind[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:
-                               {
-                                       // update each dylib load command with the timestamp of the target dylib
-                                       struct dylib_command* dylib  = (struct dylib_command*)cmd;
-                                       const char* name = (char*)cmd + dylib->dylib.name.offset;
-                                       for (const DependentLibrary* dl=fLibraries; dl < &fLibraries[fLibrariesCount]; dl++) {
-                                               if (strcmp(dl->name, name) == 0 ) {
-                                                       // found matching DependentLibrary for this load command
-                                                       if ( dl->image == NULL ) {
-                                                               // missing weak linked dylib
-                                                               dylib->dylib.timestamp = 0;
-                                                       }
-                                                       else {
-                                                               ImageLoaderMachO* targetImage = (ImageLoaderMachO*)(dl->image); // !!! assume only mach-o images are prebound
-                                                               if ( ! targetImage->isPrebindable() )
-                                                                       throw "dependent dylib is not prebound";
-                                                               // if the target is currently being re-prebound then its timestamp will be the same as this one
-                                                               if ( ! targetImage->usablePrebinding(context) ) {
-                                                                       dylib->dylib.timestamp = timestamp;
-                                                               }
-                                                               else {
-                                                                       // otherwise dependent library is already correctly prebound, so use its checksum
-                                                                       dylib->dylib.timestamp = targetImage->doGetLibraryInfo().checksum;
-                                                               }
-                                                       }
-                                                       break;
-                                               }
-                                       }
-                               }
-                               break;
-                       case LC_ID_DYLIB:
-                               {
-                                       // update the ID of this library with the new timestamp
-                                       struct dylib_command* dylib  = (struct dylib_command*)cmd;
-                                       dylib->dylib.timestamp = timestamp;
-                               }
-                               break;
-                       case LC_SEGMENT_COMMAND:
-                               // if dylib was rebased, update segment commands
-                               if ( fSlide != 0 ) {
-                                       struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-                                       seg->vmaddr += fSlide;
-                                       struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
-                                       struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
-                                       for (struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-                                               sect->addr += fSlide;
-                                       }
-                               }
-                               break;
-                       case LC_ROUTINES_COMMAND:
-                               // if dylib was rebased, update -init command
-                               if ( fSlide != 0 ) {
-                                       struct macho_routines_command* routines = (struct macho_routines_command*)cmd;
-                                       routines->init_address += fSlide;
-                               }
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }       
+       return SegmentIterator(&fSegmentsArray[fSegmentsArrayCount]);
 }
 
-void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext& context, uint8_t* fileToPrebind)
+SegmentMachO::SegmentMachO(const struct macho_segment_command* cmd)
+ : fSegmentLoadCommand(cmd)
 {
-       // In prebound images, the n_value of the symbol table entry for is the prebound address
-       // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers
-       const char* stringPool = NULL;
-       struct macho_nlist* symbolTable = NULL;
-       const struct dysymtab_command* dysymtab = NULL;
-       
-       // get symbol table info
-       macho_header* mh = (macho_header*)fileToPrebind;
-       const uint32_t cmd_count = mh->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fileToPrebind[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;
-                                       stringPool = (const char*)&fileToPrebind[symtab->stroff];
-                                       symbolTable = (struct macho_nlist*)(&fileToPrebind[symtab->symoff]);
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               dysymtab = (struct dysymtab_command*)cmd;
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }       
-
-       // walk all imports and re-resolve their n_value (needed incase prebinding is invalid)
-       struct macho_nlist* lastImport = &symbolTable[dysymtab->iundefsym+dysymtab->nundefsym];
-       for (struct macho_nlist* entry = &symbolTable[dysymtab->iundefsym]; entry < lastImport; ++entry) {
-               ImageLoader* dummy;
-               entry->n_value = this->resolveUndefined(context, entry, this->usesTwoLevelNameSpace(), &dummy);
-       }
-       
-       // walk all exports and slide their n_value
-       struct macho_nlist* lastExport = &symbolTable[dysymtab->iextdefsym+dysymtab->nextdefsym];
-       for (struct macho_nlist* entry = &symbolTable[dysymtab->iextdefsym]; entry < lastExport; ++entry) {
-               if ( (entry->n_type & N_TYPE) == N_SECT )
-                       entry->n_value += fSlide;
-       }
-
-       // walk all local symbols and slide their n_value
-       struct macho_nlist* lastLocal = &symbolTable[dysymtab->ilocalsym+dysymtab->nlocalsym];
-       for (struct macho_nlist* entry = &symbolTable[dysymtab->ilocalsym]; entry < lastLocal; ++entry) {
-               if ( entry->n_sect != NO_SECT )
-                       entry->n_value += fSlide;
-       }
-       
-       // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value
-       relocation_info* const relocsStart = (struct relocation_info*)(&fileToPrebind[dysymtab->locreloff]);
-       relocation_info* const relocsEnd = &relocsStart[dysymtab->nlocrel];
-       for (relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
-               if ( (reloc->r_address & R_SCATTERED) != 0 ) {
-                       struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
-                       if (sreloc->r_length == RELOC_SIZE) {
-                               switch(sreloc->r_type) {
-               #if __ppc__ || __ppc64__
-                                       case PPC_RELOC_PB_LA_PTR:
-               #elif __i386__ || __x86_64__
-                                       case GENERIC_RELOC_PB_LA_PTR:
-               #else
-                       #error unknown architecture
-               #endif
-                                               sreloc->r_value += fSlide;
-                                               break;
-                               }
-                       }
-               }
-       }
-       
-       // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent)
-       if ( dysymtab->nmodtab != 0 ) {
-               dylib_module* const modulesStart = (struct dylib_module*)(&fileToPrebind[dysymtab->modtaboff]);
-               dylib_module* const modulesEnd = &modulesStart[dysymtab->nmodtab];
-               for (dylib_module* module=modulesStart; module < modulesEnd; ++module) {
-                       if ( module->objc_module_info_size != 0 ) {
-                               module->objc_module_info_addr += fSlide;
-                       }
-               }
-       }
-}
-
-// file on disk has been reprebound, but we are still mapped to old file
-void ImageLoaderMachO::prebindUnmap(const LinkContext& context)
-{
-       // this removes all mappings to the old file, so the kernel will unlink (delete) it.
-       //  We need to leave the load commands and __LINKEDIT in place
-       for (std::vector<class Segment*>::iterator it=fSegments.begin(); it != fSegments.end(); ++it) {
-               void* segmentAddress = (void*)((*it)->getActualLoadAddress());
-               uintptr_t segmentSize = (*it)->getSize();
-               //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
-               // save load commands at beginning of __TEXT segment
-               if ( segmentAddress == fMachOData ) {
-                       // typically load commands are one or two pages in size, so ok to alloc on stack
-                       uint32_t loadCmdSize = sizeof(macho_header) + ((macho_header*)fMachOData)->sizeofcmds;
-                       uint32_t loadCmdPages = (loadCmdSize+4095) & (-4096);
-                       uint8_t loadcommands[loadCmdPages];
-                       memcpy(loadcommands, fMachOData, loadCmdPages);
-                       // unmap whole __TEXT segment
-                       munmap((void*)(fMachOData), segmentSize);
-                       // allocate and copy back mach_header and load commands
-                       vm_address_t addr = (vm_address_t)fMachOData;
-                       int r2 = vm_allocate(mach_task_self(), &addr, loadCmdPages, false /*at this address*/);
-                       if ( r2 != 0 )
-                               fprintf(stderr, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages);
-                       memcpy((void*)fMachOData, loadcommands, loadCmdPages);
-                       //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
-               }
-               else if ( strcmp((*it)->getName(), "__LINKEDIT") == 0 ) {
-                       uint32_t linkEditSize = segmentSize;
-                       uint32_t linkEditPages = (linkEditSize+4095) & (-4096);
-                       void* linkEditTmp = malloc(linkEditPages);
-                       memcpy(linkEditTmp, segmentAddress, linkEditPages);
-                       // unmap whole __LINKEDIT segment
-                       munmap(segmentAddress, segmentSize);
-                       vm_address_t addr = (vm_address_t)segmentAddress;
-                       int r2 = vm_allocate(mach_task_self(), &addr, linkEditPages, false /*at this address*/);
-                       if ( r2 != 0 )
-                               fprintf(stderr, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages);
-                       memcpy(segmentAddress, linkEditTmp, linkEditPages);
-                       //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
-                       free(linkEditTmp);
-               }
-               else {
-                       // unmap any other segment
-                       munmap((void*)(segmentAddress), (*it)->getSize());
-               }
-       }
 }
 
-
-
-SegmentMachO::SegmentMachO(const struct macho_segment_command* cmd, ImageLoaderMachO* image, const uint8_t* fileData)
- : fImage(image), fSize(cmd->vmsize), fFileSize(cmd->filesize), fFileOffset(cmd->fileoff), fPreferredLoadAddress(cmd->vmaddr), 
-       fVMProtection(cmd->initprot), fHasFixUps(false), fUnMapOnDestruction(false)
+SegmentMachO::~SegmentMachO()
 {
-       strncpy(fName, cmd->segname, 16);
-       fName[16] = '\0';
-       // scan sections for fix-up bit
-       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)cmd + sizeof(struct macho_segment_command));
-       const struct macho_section* const sectionsEnd = &sectionsStart[cmd->nsects];
-       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-               if ( (sect->flags & (S_ATTR_EXT_RELOC | S_ATTR_LOC_RELOC)) != 0 )
-                       fHasFixUps = true;
-       }
 }
 
-SegmentMachO::~SegmentMachO()
+void SegmentMachO::adjust(const struct macho_segment_command* cmd)
 {
-       if ( fUnMapOnDestruction ) {
-               //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress());
-               munmap((void*)(this->getActualLoadAddress()), this->getSize());
-       }
+       fSegmentLoadCommand = cmd;
 }
 
-const ImageLoader* SegmentMachO::getImage()
+void SegmentMachO::unmap(const ImageLoader* image)
 {
-       return fImage;
+       // update stats
+       --ImageLoader::fgTotalSegmentsMapped;
+       ImageLoader::fgTotalBytesMapped -= fSegmentLoadCommand->vmsize;
+       munmap((void*)(this->getActualLoadAddress(image)), fSegmentLoadCommand->vmsize);
 }
 
+
 const char* SegmentMachO::getName()
 {
-       return fName;
+       return fSegmentLoadCommand->segname;
 }
 
 uintptr_t SegmentMachO::getSize()
 {
-       return fSize;
+       return fSegmentLoadCommand->vmsize;
 }
 
 uintptr_t SegmentMachO::getFileSize()
 {
-       return fFileSize;
+       return fSegmentLoadCommand->filesize;
 }
 
 uintptr_t SegmentMachO::getFileOffset()
 {
-       return fFileOffset;
+       return fSegmentLoadCommand->fileoff;
 }
 
 bool SegmentMachO::readable()
 {
-       return ( (fVMProtection & VM_PROT_READ) != 0);
+       return ( (fSegmentLoadCommand->initprot & VM_PROT_READ) != 0);
 }
 
 bool SegmentMachO::writeable()
 {
-       return ((fVMProtection & VM_PROT_WRITE) != 0);
+       return ((fSegmentLoadCommand->initprot & VM_PROT_WRITE) != 0);
 }
 
 bool SegmentMachO::executable()
 {
-       return ((fVMProtection & VM_PROT_EXECUTE) != 0);
+       return ((fSegmentLoadCommand->initprot & VM_PROT_EXECUTE) != 0);
 }
 
 bool SegmentMachO::unaccessible()
 {
-       return (fVMProtection == 0);
+       return (fSegmentLoadCommand->initprot == 0);
 }
 
+#if TEXT_RELOC_SUPPORT
 bool SegmentMachO::hasFixUps()
 {
-       return fHasFixUps;
+       // 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;
+       }
+       return false;
 }
+#endif
 
-uintptr_t SegmentMachO::getActualLoadAddress()
+#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)
 {
-       return fPreferredLoadAddress + fImage->fSlide;
+       return fSegmentLoadCommand->vmaddr + inImage->getSlide();
 }
 
 uintptr_t SegmentMachO::getPreferredLoadAddress()
 {
-       return fPreferredLoadAddress;
+       return fSegmentLoadCommand->vmaddr;
 }
 
 bool SegmentMachO::hasPreferredLoadAddress()
 {
-       return (fPreferredLoadAddress != 0);
+       return (fSegmentLoadCommand->vmaddr != 0);
 }
 
-void SegmentMachO::setUnMapWhenDestructed(bool unmap)
-{
-       fUnMapOnDestruction = unmap;
-}
 
-static uint32_t *buildCRCTable(void)
+Segment* SegmentMachO::next(Segment* location)
 {
-       uint32_t *table = new uint32_t[256];
-       uint32_t p = 0xedb88320UL;  // standard CRC-32 polynomial
-
-       for (unsigned int i = 0; i < 256; i++) {
-               uint32_t c = i;
-               for (unsigned int j = 0; j < 8; j++) {
-                       if ( c & 1 ) c = p ^ (c >> 1);
-                       else c = c >> 1;
-               }
-               table[i] = c;
-       }
-
-       return table;
+       return &((SegmentMachO*)location)[1];
 }
 
-uint32_t SegmentMachO::crc32()
-{
-       if ( !readable() ) return 0;
-
-       static uint32_t *crcTable = NULL;
-       if ( !crcTable ) crcTable = buildCRCTable();
-       
-       uint32_t crc = ~(uint32_t)0;
-       uint8_t *p = (uint8_t *)getActualLoadAddress(); 
-       uint8_t *end = p + getSize();
-       while ( p < end ) {
-               crc = crcTable[(crc & 0xff) ^ (*p++)] ^ (crc >> 8);
-       }
-       return crc ^ ~(uint32_t)0;
-}
 
 
 
index 4e33955f6898a0d28b912d0ab49b42b91d8ecb70..a7f2c413f8861092ac607d9b1980722a80a84a3b 100644 (file)
 #include <stdint.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
@@ -43,16 +45,18 @@ 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();
 
        const char*                                                     getInstallPath() const;
        virtual void*                                           getMain() const;
        virtual const struct mach_header*   machHeader() const;
        virtual uintptr_t                                       getSlide() const;
-       virtual const void*                                     getBaseAddress() const;
+       virtual const void*                                     getEnd() const;
        virtual bool                                            hasCoalescedExports() const;
-       virtual const Symbol*                           findExportedSymbol(const char* name, const void* hint, bool searchReExports, ImageLoader** foundIn) const;
-       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym) const;
+       virtual const Symbol*                           findExportedSymbol(const char* name, const void* hint, 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;
        virtual uint32_t                                        getExportedSymbolCount() const;
@@ -66,9 +70,13 @@ public:
        virtual bool                                            forceFlat() const;
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
        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 bool                                            findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset);
        virtual bool                                            usablePrebinding(const LinkContext& context) const;
@@ -81,12 +89,14 @@ protected:
        void                            operator=(const ImageLoaderMachO&);
 
        virtual uint32_t        doGetDependentLibraryCount();
-       virtual void            doGetDependentLibraries(DependentLibrary libs[]);
+       virtual void            doGetDependentLibraries(DependentLibraryInfo libs[]);
        virtual LibraryInfo doGetLibraryInfo();
+       virtual void            getRPaths(const LinkContext& context, std::vector<const char*>&) const;
        virtual void            doRebase(const LinkContext& context);
-       virtual void            doBind(const LinkContext& context, BindingLaziness bindness);
+       virtual void            doBind(const LinkContext& context, bool forceLazysBound);
+       virtual void            doUpdateMappingPermissions(const LinkContext& context);
        virtual void            doInitialization(const LinkContext& context);
-       virtual void            doPrebinding(const LinkContext& context, time_t timestamp, uint8_t* fileToPrebind);
+       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;      
@@ -96,9 +106,10 @@ protected:
        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 void            prebindUnmap(const LinkContext& context);
+       virtual SegmentIterator beginSegments() const;
+       virtual SegmentIterator endSegments() const;
 
-#if !__LP64__   // split segs not supported for 64-bits
+#if SPLIT_SEG_DYLIB_SUPPORT
        virtual void            mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
 #endif 
                
@@ -107,37 +118,44 @@ private:
 
                        void            init();
                        void            parseLoadCmds();
-                       uintptr_t       bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, ImageLoader* targetImage, const LinkContext& context);
-                       void            doBindIndirectSymbolPointers(const LinkContext& context, BindingLaziness bindness, bool onlyCoalescedSymbols);
+                       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, ImageLoader **foundIn);
+                       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);
+                       void            resetPreboundLazyPointers(const LinkContext& context, uintptr_t relocBase);
                        void            doImageInit(const LinkContext& context);
                        void            doModInitFunctions(const LinkContext& context);
                        void            setupLazyPointerHandler(const LinkContext& context);
-                       void            applyPrebindingToDATA(uint8_t* fileToPrebind);
-                       void            applyPrebindingToLoadCommands(const LinkContext& context, uint8_t* fileToPrebind, time_t timestamp);
-                       void            applyPrebindingToLinkEdit(const LinkContext& context, uint8_t* fileToPrebind);
-#if !__LP64__   // split segs not supported for 64-bits
+                       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);
-                       int                     sharedRegionMapFilePrivateOutside(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
                        void            initMappingTable(uint64_t offsetInFat, sf_mapping *mappingTable, uintptr_t baseAddress);
-                       void            initMappingTable(uint64_t offsetInFat, _shared_region_mapping_np *mappingTable);
 #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
                        
        static  bool                            symbolRequiresCoalescing(const struct macho_nlist* symbol); 
        static uintptr_t                        bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
-       static const struct macho_nlist*  binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount);
-       static 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 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;
                        
        const uint8_t*                                                  fMachOData;
        const uint8_t*                                                  fLinkEditBase; // add any internal "offset" to this to get actual address
@@ -145,20 +163,32 @@ private:
        const char*                                                             fStrings;
        const struct dysymtab_command*                  fDynamicInfo;
        uintptr_t                                                               fSlide;
-       bool                                                                    fIsSplitSeg;
-       bool                                                                    fHasSubLibraries;
-       bool                                                                    fHasSubUmbrella;
-       bool                                                                    fTextSegmentHasFixups;
-       const struct macho_routines_command*    fDashInit;
-       const struct macho_section*                             fModInitSection;
-       const struct macho_section*                             fModTermSection;
-       const struct macho_section*                             fDATAdyld;
-       const struct macho_section*                             fImageNotifySection;
        const struct twolevel_hints_command*    fTwoLevelHints;
        const struct dylib_command*                             fDylibID;
-       const char*                                                             fReExportThruFramework;
+       class SegmentMachO*                                             fSegmentsArray;
+#if TEXT_RELOC_SUPPORT
        class SegmentMachO*                                             fTextSegmentWithFixups; // NULL unless __TEXT segment has fixups
-
+#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,
+#endif
+                                                                                       fHasSubLibraries : 1,
+                                                                                       fHasSubUmbrella : 1,
+                                                                                       fInUmbrella : 1,
+                                                                                       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;
@@ -168,10 +198,9 @@ private:
 class SegmentMachO : public Segment
 {
 public:        
-                                                               SegmentMachO(const struct macho_segment_command* cmd, ImageLoaderMachO*, const uint8_t* fileData);
+                                                               SegmentMachO(const struct macho_segment_command* cmd);
        virtual                                         ~SegmentMachO();
                                                                
-       virtual const ImageLoader*      getImage();
        virtual const char*                     getName();
        virtual uintptr_t                       getSize();
        virtual uintptr_t                       getFileSize();
@@ -180,31 +209,27 @@ public:
        virtual bool                            writeable();
        virtual bool                            executable();
        virtual bool                            unaccessible();
-       virtual bool                            hasFixUps();
-       virtual uintptr_t                       getActualLoadAddress();
+       virtual uintptr_t                       getActualLoadAddress(const ImageLoader*);
        virtual uintptr_t                       getPreferredLoadAddress();
-       virtual void                            setUnMapWhenDestructed(bool unmap);
-       virtual uint32_t                        crc32();
-
+       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;
        
-
-       ImageLoaderMachO* const fImage;
-       char                                    fName[18];
-       const uintptr_t                 fSize;
-       const uintptr_t                 fFileSize;
-       const uintptr_t                 fFileOffset;
-       const uintptr_t                 fPreferredLoadAddress;
-       const uint16_t                  fVMProtection;
-       bool                                    fHasFixUps;
-       bool                                    fUnMapOnDestruction;
+       const struct macho_segment_command*             fSegmentLoadCommand;
 };
 
 
index 4d875e4896c3fbfa9b1a563d24fffdefa5b55298..8d340ad2651e336d632105f16ea2eac3bc430346 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,6 +25,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/param.h>
 #include <mach/mach_time.h> // mach_absolute_time()
 #include <sys/stat.h> 
 #include <mach-o/fat.h> 
 #include <mach-o/loader.h> 
+#include <mach-o/ldsyms.h> 
 #include <libkern/OSByteOrder.h> 
 #include <mach/mach.h>
 #include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <sys/dtrace.h>
 
 #include <vector>
+#include <algorithm>
 
 #include "mach-o/dyld_gdb.h"
 
 #include "dyld.h"
 #include "ImageLoader.h"
 #include "ImageLoaderMachO.h"
-#include "dyldLibSystemThreadHelpers.h"
+#include "dyldLibSystemInterface.h"
+#include "dyld_cache_format.h"
+
+// from _simple.h in libc
+typedef struct _SIMPLE*                _SIMPLE_STRING;
+extern "C" void                                _simple_vdprintf(int __fd, const char *__fmt, va_list __ap);
+extern "C" void                                _simple_dprintf(int __fd, const char *__fmt, ...);
+extern "C" _SIMPLE_STRING      _simple_salloc(void);
+extern "C" int                         _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap);
+extern "C" void                                _simple_sfree(_SIMPLE_STRING __b);
+extern "C" char *                      _simple_string(_SIMPLE_STRING __b);
+
+
+
+// 32-bit ppc is only architecture that uses cpu-sub-types
+#define CPU_SUBTYPES_SUPPORTED __ppc__ 
+
+
+#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__
 
 
 #define CPU_TYPE_MASK 0x00FFFFFF       /* complement of CPU_ARCH_MASK */
 
 
 /* implemented in dyld_gdb.cpp */
-void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
-void removeImageFromAllImages(const mach_header* mh);
+extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
+extern void removeImageFromAllImages(const mach_header* mh);
 #if OLD_GDB_DYLD_INTERFACE
-void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath);
-void removeImageForgdb(const struct mach_header* mh);
+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
 
 // magic so CrashReporter logs message
 extern "C" {
        char error_string[1024];
 }
+// implemented in dyldStartup.s for CrashReporter
+extern "C" void dyld_fatal_error(const char* errString) __attribute__((noreturn));
+
 
 
 //
@@ -93,6 +119,7 @@ struct EnvironmentVariables {
        bool                                            DYLD_PRINT_STATISTICS;
        bool                                            DYLD_PRINT_OPTS;
        bool                                            DYLD_PRINT_ENV;
+       bool                                            DYLD_DISABLE_DOFS;
                                                        //      DYLD_IMAGE_SUFFIX                               ==> gLinkContext.imageSuffix
                                                        //      DYLD_PRINT_OPTS                                 ==> gLinkContext.verboseOpts
                                                        //      DYLD_PRINT_ENV                                  ==> gLinkContext.verboseEnv
@@ -101,28 +128,37 @@ struct EnvironmentVariables {
                                                        //      DYLD_PRINT_SEGMENTS                             ==> gLinkContext.verboseMapping
                                                        //      DYLD_PRINT_BINDINGS                             ==> gLinkContext.verboseBind
                                                        //      DYLD_PRINT_REBASINGS                    ==> gLinkContext.verboseRebase
+                                                       //      DYLD_PRINT_DOFS                                 ==> gLinkContext.verboseDOF
                                                        //      DYLD_PRINT_APIS                                 ==> gLogAPIs
                                                        //      DYLD_IGNORE_PREBINDING                  ==> gLinkContext.prebindUsage
                                                        //      DYLD_PREBIND_DEBUG                              ==> gLinkContext.verbosePrebinding
                                                        //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode
-                                                       //      DYLD_SLIDE_AND_PACK_DYLIBS              ==> gLinkContext.slideAndPackDylibs
                                                        //      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 cpu_type_t                                      sHostCPU;
 static cpu_subtype_t                           sHostCPUsubtype;
 static ImageLoader*                                    sMainExecutable = NULL;
-static bool                                                    sAllImagesMightContainUnlinkedImages;    // necessary until will support dylib unloading
+static bool                                                    sMainExecutableIsSetuid = 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];
+static StateHandlers                           sBatchHandlers[7];
 static ImageLoader*                                    sLastImageByAddressCache;
 static EnvironmentVariables                    sEnv;
 static const char*                                     sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
@@ -130,10 +166,67 @@ static const char*                                        sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib"
 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;
+#endif
 ImageLoader::LinkContext                       gLinkContext;
 bool                                                           gLogAPIs = false;
-const struct ThreadingHelpers*         gThreadHelpers = NULL;
+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
+
+
+
+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;
+}
+
+
+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;
+}
+
+void log(const char* format, ...) 
+{
+       va_list list;
+       va_start(list, format);
+       _simple_vdprintf(STDERR_FILENO, format, list);
+       va_end(list);
+}
 
+void warn(const char* format, ...) 
+{
+       _simple_dprintf(STDERR_FILENO, "dyld: warning, ");
+       va_list list;
+       va_start(list, format);
+       _simple_vdprintf(STDERR_FILENO, format, list);
+       va_end(list);
+}
 
 
 // utility class to assure files are closed when an exception is thrown
@@ -147,78 +240,324 @@ private:
 };
 
 FileOpener::FileOpener(const char* path)
+ : fd(-1)
 {
        fd = open(path, O_RDONLY, 0);
 }
 
 FileOpener::~FileOpener()
 {
-       close(fd);
+       if ( fd != -1 )
+               close(fd);
 }
 
 
+// forward declaration
+#if __ppc__ || __i386__
+bool isRosetta();
+#endif
+
 
-// Objective-C installs an addImage hook to dyld to get notified about new images
-// The callback needs to be run after the image is rebased and bound, but before its initializers are called
-static uint32_t imageNotification(ImageLoader* image, uint32_t startIndex)
+static void    registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
 {
-       // tell all register add image handlers about this
-       const uint32_t callbackCount = sAddImageCallbacks.size();
-       for (uint32_t i=startIndex; i < callbackCount; ++i) {
-               ImageCallback cb = sAddImageCallbacks[i];
-               //fprintf(stderr, "dyld: calling add-image-callback[%d]=%p for %s\n", i, cb, image->getPath());
-               (cb)(image->machHeader(), image->getSlide());
+#if __ppc__
+       // can't dtrace a program running emulated under rosetta rdar://problem/5179640
+       if ( isRosetta() )
+               return;
+#endif
+       const unsigned int dofSectionCount = dofs.size();
+       if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
+               int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
+               if ( fd < 0 ) {
+                       //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
+               }
+               else {
+                       // allocate a buffer on the stack for the variable length dof_ioctl_data_t type
+                       uint8_t buffer[sizeof(dof_ioctl_data_t) + dofSectionCount*sizeof(dof_helper_t)];
+                       dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
+                       
+                       // fill in buffer with one dof_helper_t per DOF section
+                       ioctlData->dofiod_count = dofSectionCount;
+                       for (unsigned int i=0; i < dofSectionCount; ++i) {
+                               strlcpy(ioctlData->dofiod_helpers[i].dofhp_mod, dofs[i].imageShortName, DTRACE_MODNAMELEN);
+                               ioctlData->dofiod_helpers[i].dofhp_dof = (uintptr_t)(dofs[i].dof);
+                               ioctlData->dofiod_helpers[i].dofhp_addr = (uintptr_t)(dofs[i].dof);
+                       }
+                       
+                       // tell kernel about all DOF sections en mas
+                       // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
+                       user_addr_t val = (user_addr_t)(unsigned long)ioctlData;
+                       if ( ioctl(fd, DTRACEHIOC_ADDDOF, &val) != -1 ) {
+                               // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
+                               for (unsigned int i=0; i < dofSectionCount; ++i) {
+                                       RegisteredDOF info;
+                                       info.mh = dofs[i].imageHeader;
+                                       info.registrationID = (int)(ioctlData->dofiod_helpers[i].dofhp_dof);
+                                       sImageFilesNeedingDOFUnregistration.push_back(info);
+                                       if ( gLinkContext.verboseDOF ) {
+                                               dyld::log("dyld: registering DOF section 0x%p in %s with dtrace, ID=0x%08X\n", 
+                                                       dofs[i].dof, dofs[i].imageShortName, info.registrationID);
+                                       }
+                               }
+                       }
+                       else {
+                               dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
+                       }
+                       close(fd);
+               }
+       }
+}
+
+static void    unregisterDOF(int registrationID)
+{
+       int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
+       if ( fd < 0 ) {
+               dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to unregister dtrace DOF section\n");
+       }
+       else {
+               ioctl(fd, DTRACEHIOC_REMOVE, registrationID);
+               close(fd);
+               if ( gLinkContext.verboseInit )
+                       dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID);
        }
-       return callbackCount;
 }
 
 
+//
+// _dyld_register_func_for_add_image() is implemented as part of the general image state change notification
+//
+static void notifyAddImageCallbacks(ImageLoader* image)
+{
+       for (std::vector<ImageCallback>::iterator it=sAddImageCallbacks.begin(); it != sAddImageCallbacks.end(); it++)
+               (*it)(image->machHeader(), image->getSlide());
+}
+
+
+// notify gdb about these new images
+static const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       addImagesToAllImages(infoCount, info);
+       return NULL;
+}
 
-// notify gdb et al about these new images
-static void notifyAdding(std::vector<ImageLoader*>& images)
+#if IMAGE_NOTIFY_SUPPORT
+// notify objc about these new images
+static void notifyAdding(const ImageLoader* const * images, unsigned int count)
 {
        // build array
-       unsigned int len = images.size();
-       if ( len != 0 ) {
-               dyld_image_info infos[len];
-               for (unsigned int i=0; i < len; ++i) {
+       if ( count != 0 ) {
+               dyld_image_info infos[count];
+               for (unsigned int i=0; i < count; ++i) {
                        dyld_image_info* p = &infos[i];
-                       ImageLoader* image = images[i];
+                       const ImageLoader* image = images[i];
                        p->imageLoadAddress = image->machHeader();
                        p->imageFilePath = image->getPath();
                        p->imageFileModDate = image->lastModified();
-                       //fprintf(stderr, "notifying objc about %s\n", image->getPath());
+                       //dyld::log("notifying objc about %s\n", image->getPath());
                }
                
-               // tell gdb
-               addImagesToAllImages(len, infos);
-                               
                // 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, len, infos);
+                       (*it)->doNotification(dyld_image_adding, count, infos);
+               }
+       }
+}
+#endif
+
+static StateHandlers* stateToHandlers(dyld_image_states state, StateHandlers handlersArray[8]) 
+{
+       switch ( state ) {
+               case dyld_image_state_mapped:
+                       return &handlersArray[0];
+                       
+               case dyld_image_state_dependents_mapped:
+                       return &handlersArray[1];
+                       
+               case dyld_image_state_rebased:
+                       return &handlersArray[2];
+                       
+               case dyld_image_state_bound:
+                       return &handlersArray[3];
+                       
+               case dyld_image_state_dependents_initialized:
+                       return &handlersArray[4];
+
+               case dyld_image_state_initialized:
+                       return &handlersArray[5];
+                       
+               case dyld_image_state_terminated:
+                       return &handlersArray[6];
+       }
+       return NULL;
+}
+
+static void notifySingle(dyld_image_states state, const struct mach_header* mh, const char* path, time_t modDate)
+{
+       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;
+               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) ) {
+                               //fprintf(stderr, "  image rejected by handler=%p\n", *it);
+                               // make copy of thrown string so that later catch clauses can free it
+                               const char* str = strdup(result);
+                               throw str;
+                       }
                }
        }
 }
 
 
 
+static int imageSorter(const void* l, const void* r)
+{
+       const ImageLoader* left = *((ImageLoader**)l);
+       const ImageLoader* right= *((ImageLoader**)r);
+       return left->compare(right);
+}
+
+static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image_state_change_handler onlyHandler)
+{
+       std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
+       if ( handlers != NULL ) {
+               // don't use a vector because it will use malloc/free and we want notifcation to be low cost
+               ImageLoader* images[sAllImages.size()+1];
+               ImageLoader** end = images;
+               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+                       dyld_image_states imageState = (*it)->getState();
+                       if ( (imageState == state) || (orLater && (imageState > state)) )
+                               *end++ = *it;
+               }
+               if ( sBundleBeingLoaded != NULL ) {
+                       dyld_image_states imageState = sBundleBeingLoaded->getState();
+                       if ( (imageState == state) || (orLater && (imageState > state)) )
+                               *end++ = sBundleBeingLoaded;
+               }
+               unsigned int count = end-images;
+               if ( end != images ) {
+                       // sort bottom up
+                       qsort(images, count, sizeof(ImageLoader*), &imageSorter);
+                       // build info array
+                       dyld_image_info infos[count];
+                       for (unsigned int i=0; i < count; ++i) {
+                               dyld_image_info* p = &infos[i];
+                               ImageLoader* image = images[i];
+                               //dyld::log("  state=%d, name=%s\n", state, image->getPath());
+                               p->imageLoadAddress = image->machHeader();
+                               p->imageFilePath = image->getPath();
+                               p->imageFileModDate = image->lastModified();
+                               // special case for add_image hook
+                               if ( state == dyld_image_state_bound )
+                                       notifyAddImageCallbacks(image);
+                       }
+                       
+                       if ( onlyHandler != NULL ) {
+                               const char* result = (*onlyHandler)(state, count, infos);
+                               if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
+                                       //fprintf(stderr, "  images rejected by handler=%p\n", onlyHandler);
+                                       // make copy of thrown string so that later catch clauses can free it
+                                       const char* str = strdup(result);
+                                       throw str;
+                               }
+                       }
+                       else {
+                               // call each handler with whole array 
+                               for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
+                                       const char* result = (*it)(state, count, infos);
+                                       if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
+                                               //fprintf(stderr, "  images rejected by handler=%p\n", *it);
+                                               // make copy of thrown string so that later catch clauses can free it
+                                               const char* str = strdup(result);
+                                               throw str;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static void notifyBatch(dyld_image_states state)
+{
+       notifyBatchPartial(state, false, NULL);
+}
+
 // In order for register_func_for_add_image() callbacks to to be called bottom up,
 // we need to maintain a list of root images. The main executable is usally the
 // first root. Any images dynamically added are also roots (unless already loaded).
 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
 static void addRootImage(ImageLoader* image)
 {
-       //fprintf(stderr, "addRootImage(%p, %s)\n", image, image->getPath());
+       //dyld::log("addRootImage(%p, %s)\n", image, image->getPath());
        // add to list of roots
        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()
+{
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
+               (*it)->clearDepth();
+}
+
+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)
+{
+       // make a copy of the pointers to program variables
+       gLinkContext.programVars = newVars;
+       
+       // now set each program global to their initial value
+       *gLinkContext.programVars.NXArgcPtr = gLinkContext.argc;
+       *gLinkContext.programVars.NXArgvPtr = gLinkContext.argv;
+       *gLinkContext.programVars.environPtr = gLinkContext.envp;
+       *gLinkContext.programVars.__prognamePtr = gLinkContext.progname;
+}
+
+#if SUPPORT_OLD_CRT_INITIALIZATION
+static void setRunInitialzersOldWay()
+{
+       gRunInitializersOldWay = true;          
+}
+#endif
 
 static void addImage(ImageLoader* image)
 {
@@ -226,11 +565,7 @@ static void addImage(ImageLoader* image)
        sAllImages.push_back(image);
        
        if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
-               uint64_t offset = image->getOffsetInFatFile();
-               if ( offset == 0 )
-                       fprintf(stderr, "dyld: loaded: %s\n", image->getPath());
-               else
-                       fprintf(stderr, "dyld: loaded: %s, cpu-sub-type: %d\n", image->getPath(), image->machHeader()->cpusubtype);
+               dyld::log("dyld: loaded: %s\n", image->getPath());
        }
        
 #if OLD_GDB_DYLD_INTERFACE
@@ -250,12 +585,27 @@ void removeImage(ImageLoader* image)
                }
        }
        
+       // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
+       for (std::vector<RegisteredDOF>::iterator it=sImageFilesNeedingDOFUnregistration.begin(); it != sImageFilesNeedingDOFUnregistration.end(); ) {
+               if ( it->mh == image->machHeader() ) {
+                       unregisterDOF(it->registrationID);
+                       sImageFilesNeedingDOFUnregistration.erase(it);
+                       // don't increment iterator, the erase caused next element to be copied to where this iterator points
+               }
+               else {
+                       ++it;
+               }
+       }
+       
        // tell all register add image handlers about this
-       // do this before removing image from internal data structures so that the callback can querey dyld about the image
-       for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
-               (*it)(image->machHeader(), image->getSlide());
+       // 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++) {
+                       (*it)(image->machHeader(), image->getSlide());
+               }
        }
        
+#if IMAGE_NOTIFY_SUPPORT
        // tell all interested images
        for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
                dyld_image_info info;
@@ -264,6 +614,7 @@ void removeImage(ImageLoader* image)
                info.imageFileModDate = image->lastModified();
                (*it)->doNotification(dyld_image_removing, 1, &info);
        }
+#endif
 
        // remove from master list
        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -273,10 +624,11 @@ void removeImage(ImageLoader* image)
                }
        }
        
-       // flush find-by-address cache
+       // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
        if ( sLastImageByAddressCache == image )
                sLastImageByAddressCache = NULL;
 
+#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 ) {
@@ -284,6 +636,7 @@ void removeImage(ImageLoader* image)
                        break;
                }
        }
+#endif
 
        // if in root list, pull it out 
        for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
@@ -293,6 +646,11 @@ void removeImage(ImageLoader* image)
                }
        }
 
+       // log if requested
+       if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
+               dyld::log("dyld: unloaded: %s\n", image->getPath());
+       }
+
        // tell gdb, new way
        removeImageFromAllImages(image->machHeader());
 
@@ -317,22 +675,28 @@ const char* getExecutablePath()
 
 void initializeMainExecutable()
 {
+
+#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();
-       for(int i=0; i < rootCount; ++i) {
-               ImageLoader* image = sImageRoots[i];
-               //fprintf(stderr, "initializeMainExecutable: image = %p\n", image);
-               image->runInitializers(gLinkContext);
-       }
-/*
-       // this does not work???
-       for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
-               ImageLoader* image = *it;
-               fprintf(stderr, "initializeMainExecutable: image = %p\n", image);
-               // don't know why vector sometimes starts with NULL element???
-               if ( image != NULL ) 
-                       image->runInitializers(gLinkContext);
+       if ( rootCount > 1 ) {
+               for(int i=1; i < rootCount; ++i)
+                       sImageRoots[i]->runInitializers(gLinkContext);
        }
-*/
+       
+       // run initializers for main executable and everything it brings up 
+       sMainExecutable->runInitializers(gLinkContext);
+       
+       // register atexit() handler to run terminators in all loaded images when this process exits
+       if ( gLibSystemHelpers != NULL ) 
+               (*gLibSystemHelpers->cxa_atexit)(&runTerminators, NULL, NULL);
+
+       // dump info if requested
        if ( sEnv.DYLD_PRINT_STATISTICS )
                ImageLoaderMachO::printStatistics(sAllImages.size());
 }
@@ -348,14 +712,16 @@ ImageLoader* mainExecutable()
 }
 
 
-void runTerminators()
+void runTerminators(void* extra)
 {
        const unsigned int imageCount = sImageFilesNeedingTermination.size();
        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);
 }
 
 
@@ -397,6 +763,7 @@ static const char** parseColonList(const char* list)
        return (const char**)result;
 }
 
 static void paths_expand_roots(const char **paths, const char *key, const char *val)
 {
 //     assert(val != NULL);
@@ -417,14 +784,19 @@ static void paths_expand_roots(const char **paths, const char *key, const char *
 
 static void removePathWithPrefix(const char* paths[], const char* prefix)
 {
-       size_t prefixLen = strlen(prefix);
-       for(int s=0,d=0; (paths[d] != NULL) && (paths[s] != NULL); ++s, ++d) {
-               if ( strncmp(paths[s], prefix, prefixLen) == 0 )
-                       ++s;
-               paths[d] = paths[s];
-       }
+    size_t prefixLen = strlen(prefix);
+    int skip = 0;
+    int i;
+    for(i = 0; paths[i] != NULL; ++i) {
+        if ( strncmp(paths[i], prefix, prefixLen) == 0 )
+            ++skip;
+        else
+            paths[i-skip] = paths[i];
+    }
+    paths[i-skip] = NULL;
 }
 
+
 #if 0
 static void paths_dump(const char **paths)
 {
@@ -432,7 +804,7 @@ static void paths_dump(const char **paths)
   const char **strs = paths;
   while(*strs != NULL)
   {
-    fprintf(stderr, "\"%s\"\n", *strs);
+    dyld::log("\"%s\"\n", *strs);
     strs++;
   }
   return;
@@ -443,7 +815,7 @@ static void printOptions(const char* argv[])
 {
        uint32_t i = 0;
        while ( NULL != argv[i] ) {
-               fprintf(stderr, "opt[%i] = \"%s\"\n", i, argv[i]);
+               dyld::log("opt[%i] = \"%s\"\n", i, argv[i]);
                i++;
        }
 }
@@ -451,33 +823,36 @@ static void printOptions(const char* argv[])
 static void printEnvironmentVariables(const char* envp[])
 {
        while ( NULL != *envp ) {
-               fprintf(stderr, "%s\n", *envp);
+               dyld::log("%s\n", *envp);
                envp++;
        }
 }
 
-
-
 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] != '/' ) {
-                                       fprintf(stderr, "dyld: warning DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
+                                       dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
                                        sEnv.DYLD_ROOT_PATH = NULL;
                                        break;
                                }
@@ -485,16 +860,12 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                }
        } 
        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);
-       }
-       else if ( strcmp(key, "DYLD_DEBUG_TRACE") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_DEBUG_TRACE not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_ERROR_PRINT") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_ERROR_PRINT not supported\n");
+               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
                sEnv.DYLD_PRINT_OPTS = true;
@@ -502,61 +873,39 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
        else if ( strcmp(key, "DYLD_PRINT_ENV") == 0 ) {
                sEnv.DYLD_PRINT_ENV = true;
        }
+       else if ( strcmp(key, "DYLD_DISABLE_DOFS") == 0 ) {
+               sEnv.DYLD_DISABLE_DOFS = true;
+       }
+       else if ( strcmp(key, "DYLD_DISABLE_PREFETCH") == 0 ) {
+               gLinkContext.preFetchDisabled = true;
+       }
        else if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) {
                sEnv.DYLD_PRINT_LIBRARIES = true;
        }
        else if ( strcmp(key, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
                sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH = true;
        }
-       else if ( strcmp(key, "DYLD_TRACE") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_TRACE not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_EBADEXEC_ONLY") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_EBADEXEC_ONLY not supported\n");
-       }
        else if ( strcmp(key, "DYLD_BIND_AT_LAUNCH") == 0 ) {
                sEnv.DYLD_BIND_AT_LAUNCH = true;
        }
        else if ( strcmp(key, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
                gLinkContext.bindFlat = true;
        }
-       else if ( strcmp(key, "DYLD_DEAD_LOCK_HANG") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_DEAD_LOCK_HANG not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_ABORT_MULTIPLE_INITS") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_ABORT_MULTIPLE_INITS not supported\n");
-       }
        else if ( strcmp(key, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
-               gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
-       }
-       else if ( strcmp(key, "DYLD_SLIDE_AND_PACK_DYLIBS") == 0 ) {
-               gLinkContext.slideAndPackDylibs = true;
+               // ignore, no longer relevant but some scripts still set it
        }
        else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) {
-               // since the new dyld never runs fix_prebinding, no need to warn if someone does not want it run
-               //fprintf(stderr, "dyld: warning DYLD_NO_FIX_PREBINDING not supported\n");
+               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) {
                gLinkContext.verbosePrebinding = true;
        }
-       else if ( strcmp(key, "DYLD_HINTS_DEBUG") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_HINTS_DEBUG not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_SAMPLE_DEBUG") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_SAMPLE_DEBUG not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_EXECUTABLE_PATH_DEBUG") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_EXECUTABLE_PATH_DEBUG not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_TWO_LEVEL_DEBUG") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_TWO_LEVEL_DEBUG not supported\n");
-       }
-       else if ( strcmp(key, "DYLD_LAZY_INITIALIZERS") == 0 ) {
-               fprintf(stderr, "dyld: warning DYLD_LAZY_INITIALIZERS not supported\n");
-       }
        else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) {
                gLinkContext.verboseInit = true;
        }
+       else if ( strcmp(key, "DYLD_PRINT_DOFS") == 0 ) {
+               gLinkContext.verboseDOF = true;
+       }
        else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) {
                sEnv.DYLD_PRINT_STATISTICS = true;
        }
@@ -576,6 +925,7 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                gLinkContext.verboseWarnings = true;
        }
        else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
+               gSharedCacheDontNotify = true;
                if ( strcmp(value, "private") == 0 ) {
                        gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
                }
@@ -589,10 +939,11 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                        gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
                }
                else {
-                       fprintf(stderr, "dyld: warning unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n");
+                       dyld::warn("unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n");
                }
        }
        else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) {
+               gSharedCacheDontNotify = true;
                if ( strcmp(value, "all") == 0 ) {
                        gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
                }
@@ -606,14 +957,15 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                        gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
                }
                else {
-                       fprintf(stderr, "dyld: warning unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n");
+                       dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n");
                }
        }
        else {
-               fprintf(stderr, "dyld: warning, unknown environment variable: %s\n", key);
+               dyld::warn("unknown environment variable: %s\n", key);
        }
 }
 
+
 //
 // For security, setuid programs ignore DYLD_* environment variables.
 // Additionally, the DYLD_* enviroment variables are removed
@@ -621,6 +973,9 @@ 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;
@@ -642,21 +997,12 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                } while ( *d++ != NULL );
        }
        
-       // setup DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
-       if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
-               const char** paths = sFrameworkFallbackPaths;
-               removePathWithPrefix(paths, "$HOME");
-               sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths;
-       }
-
-       // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
-       if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
-               const char** paths = sLibraryFallbackPaths;
-               removePathWithPrefix(paths, "$HOME");
-               sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
-       }
+       // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
+       sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = NULL;
+       sEnv.DYLD_FALLBACK_LIBRARY_PATH = NULL;
 }
 
+
 static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
 {
        const char* home = NULL;
@@ -682,7 +1028,7 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                        sEnv.LD_LIBRARY_PATH = parseColonList(path);
                }
        }
-               
+       
        // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
        if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
                const char** paths = sFrameworkFallbackPaths;
@@ -707,7 +1053,7 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
 
 static void getHostInfo()
 {
-#if 0
+#if 1
        struct host_basic_info info;
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
        mach_port_t hostPort = mach_host_self();
@@ -718,17 +1064,30 @@ static void getHostInfo()
        
        sHostCPU                = info.cpu_type;
        sHostCPUsubtype = info.cpu_subtype;
-#endif
-
+#else
        size_t valSize = sizeof(sHostCPU);
        if (sysctlbyname ("hw.cputype", &sHostCPU, &valSize, NULL, 0) != 0) 
                throw "sysctlbyname(hw.cputype) failed";
        valSize = sizeof(sHostCPUsubtype);
        if (sysctlbyname ("hw.cpusubtype", &sHostCPUsubtype, &valSize, NULL, 0) != 0) 
                throw "sysctlbyname(hw.cpusubtype) failed";
+#endif
+}
+
+static void checkSharedRegionDisable()
+{
+       #if __ppc__ || __i386__
+       // if main executable has segments that overlap the shared region, 
+       // then disable using the shared region
+       if ( sMainExecutable->overlapsWithAddressRange((void*)0x90000000, (void*)0xAFFFFFFF) ) {
+               gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
+               if ( gLinkContext.verboseMapping )
+                       dyld::warn("disabling shared region because main executable overlaps\n");
+       }
+       #endif
 }
 
-bool validImage(ImageLoader* possibleImage)
+bool validImage(const ImageLoader* possibleImage)
 {
        const unsigned int imageCount = sAllImages.size();
        for(unsigned int i=0; i < imageCount; ++i) {
@@ -741,35 +1100,13 @@ bool validImage(ImageLoader* possibleImage)
 
 uint32_t getImageCount()
 {
-       if ( sAllImagesMightContainUnlinkedImages ) {
-               uint32_t count = 0;
-               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-                       if ( (*it)->isLinked() )
-                               ++count;
-               }
-               return count;
-       }
-       else {
-               return sAllImages.size();
-       }
+       return sAllImages.size();
 }
 
 ImageLoader* getIndexedImage(unsigned int index)
 {
-       if ( sAllImagesMightContainUnlinkedImages ) {
-               uint32_t count = 0;
-               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-                       if ( (*it)->isLinked() ) {
-                               if ( index == count )
-                                       return *it;
-                               ++count;
-                       }
-               }
-       }
-       else {
-               if ( index < sAllImages.size() )
-                       return sAllImages[index];
-       }
+       if ( index < sAllImages.size() )
+               return sAllImages[index];
        return NULL;
 }
 
@@ -792,7 +1129,7 @@ ImageLoader* findImageContainingAddress(const void* addr)
        static int cacheMiss = 0; 
        static int cacheNotMacho = 0; 
        if ( ((cacheHit+cacheMiss+cacheNotMacho) % 100) == 0 )
-               fprintf(stderr, "findImageContainingAddress(): cache hit = %d, miss = %d, unknown = %d\n", cacheHit, cacheMiss, cacheNotMacho);
+               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) ) {
@@ -922,6 +1259,8 @@ static const char* getLibraryLeafName(const char* path)
 }
 
 
+// only for architectures that use cpu-sub-types
+#if CPU_SUBTYPES_SUPPORTED 
 
 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
 
@@ -956,23 +1295,6 @@ static const cpu_subtype_t kPPC32[kPPC_RowCount][6] = {
 };
 
 
-//      
-//     64-bit PowerPC sub-type lists
-//
-const int kPPC64_RowCount = 1;
-static const cpu_subtype_t kPPC64[kPPC64_RowCount][3] = { 
-       // G5 can run any 64-bit code
-       {  CPU_SUBTYPE_POWERPC_970, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST },
-};
-
-
-
-//      
-//     32-bit x86 sub-type lists
-//
-//     TO-DO
-
-
 
 // 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)
@@ -984,15 +1306,6 @@ static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t sub
                                        return kPPC32[i];
                        }
                        break;
-               case CPU_TYPE_POWERPC64:
-                       for (int i=0; i < kPPC64_RowCount ; ++i) {
-                               if ( kPPC64[i][0] == subtype )
-                                       return kPPC64[i];
-                       }
-                       break;
-               case CPU_TYPE_I386:
-                       // To do 
-                       break;
        }
        return NULL;
 }
@@ -1007,7 +1320,7 @@ static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[
        for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) {
                for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) {
                        if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu) 
-                               && (list[subTypeIndex] == archs[fatIndex].cpusubtype) ) {
+                               && (list[subTypeIndex] == (cpu_subtype_t)OSSwapBigToHostInt32(archs[fatIndex].cpusubtype)) ) {
                                *offset = OSSwapBigToHostInt32(archs[fatIndex].offset);
                                *len = OSSwapBigToHostInt32(archs[fatIndex].size);
                                return true;
@@ -1040,33 +1353,19 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
                if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
                        switch (cpu) {
                                case CPU_TYPE_POWERPC:
-                               case CPU_TYPE_POWERPC64:
                                        if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_POWERPC_ALL ) {
                                                *offset = OSSwapBigToHostInt32(archs[i].offset);
                                                *len = OSSwapBigToHostInt32(archs[i].size);
                                                return true;
                                        }
                                        break;
-                               case CPU_TYPE_I386:
-                                       if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_I386_ALL ) {
-                                               *offset = OSSwapBigToHostInt32(archs[i].offset);
-                                               *len = OSSwapBigToHostInt32(archs[i].size);
-                                               return true;
-                                       }
-                                       break;
-                               case CPU_TYPE_X86_64:
-                                       if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_X86_64_ALL ) {
-                                               *offset = OSSwapBigToHostInt32(archs[i].offset);
-                                               *len = OSSwapBigToHostInt32(archs[i].size);
-                                               return true;
-                                       }
-                                       break;
                        }
                }
        }
        return false;
 }
 
+#endif // CPU_SUBTYPES_SUPPORTED
 
 //
 // A fat file may contain multiple sub-images for the same cpu-type,
@@ -1075,6 +1374,7 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
 //
 static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
 {
+#if CPU_SUBTYPES_SUPPORTED
        // assume all dylibs loaded must have same cpu type as main executable
        const cpu_type_t cpu = sMainExecutableMachHeader->cputype;
 
@@ -1094,20 +1394,32 @@ static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
        
        // running on an uknown cpu, can only load generic code
        return fatFindRunsOnAllCPUs(cpu, fh, offset, len);
+#else
+       // just find first slice with matching architecture
+       const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
+       for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+               if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == sMainExecutableMachHeader->cputype) {
+                       *offset = OSSwapBigToHostInt32(archs[i].offset);
+                       *len = OSSwapBigToHostInt32(archs[i].size);
+                       return true;
+               }
+       }
+       return false;
+#endif
 }
 
 
 
 //
 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
-// on the current processor.  It is deemed compatible if any of the following are true:
-//  1) mach_header subtype is in list of compatible subtypes for running processor
-//  2) mach_header subtype is same as running processor subtype
-//  3) mach_header subtype runs on all processor variants
-//
-//
+// on the current processor. //
 bool isCompatibleMachO(const uint8_t* firstPage)
 {
+#if CPU_SUBTYPES_SUPPORTED
+       // It is deemed compatible if any of the following are true:
+       //  1) mach_header subtype is in list of compatible subtypes for running processor
+       //  2) mach_header subtype is same as running processor subtype
+       //  3) mach_header subtype runs on all processor variants
        const mach_header* mh = (mach_header*)firstPage;
        if ( mh->magic == sMainExecutableMachHeader->magic ) {
                if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
@@ -1128,36 +1440,44 @@ bool isCompatibleMachO(const uint8_t* firstPage)
                                        return true;
                        }
                        
-                       // cpu unknown, so don't know if subtype is compatible
-                       // only load _ALL variant
+                       // cpu type has no ordered list of subtypes
                        switch (mh->cputype) {
                                case CPU_TYPE_POWERPC:
-                               case CPU_TYPE_POWERPC64:
+                                       // allow _ALL to be used by any client
                                        if ( mh->cpusubtype == CPU_SUBTYPE_POWERPC_ALL ) 
                                                return true;
                                        break;
+                               case CPU_TYPE_POWERPC64:
                                case CPU_TYPE_I386:
-                                       if ( mh->cpusubtype == CPU_SUBTYPE_I386_ALL ) 
-                                               return true;
-                                       break;                                  
                                case CPU_TYPE_X86_64:
-                                       if ( mh->cpusubtype == CPU_SUBTYPE_X86_64_ALL ) 
-                                               return true;
-                                       break;          
+                                       // subtypes are not used or these architectures
+                                       return true;
                        }
                }
        }
+#else
+       // For architectures that don't support cpu-sub-types
+       // this just check the cpu type.
+       const mach_header* mh = (mach_header*)firstPage;
+       if ( mh->magic == sMainExecutableMachHeader->magic ) {
+               if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
+                       return true;
+               }
+       }
+#endif
        return false;
 }
 
 
+
+
 // 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, const char* path)
+static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, uintptr_t slide, const char* path)
 {
        // try mach-o loader
        if ( isCompatibleMachO((const uint8_t*)mh) ) {
-               ImageLoader* image = new ImageLoaderMachO(path, mh, 0, gLinkContext);
+               ImageLoader* image = new ImageLoaderMachO(mh, slide, path, gLinkContext);
                addImage(image);
                return image;
        }
@@ -1165,32 +1485,91 @@ static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, con
        throw "main executable not a known format";
 }
 
+#if DYLD_SHARED_CACHE_SUPPORT
+static ImageLoader* findSharedCacheImage(const struct stat& stat_buf, const char* path)
+{
+       if ( sSharedCache != NULL ) {
+               // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
+               const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
+               const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
+               for( const dyld_cache_image_info* p = start; p != end; ++p) {
+                       // check mtime and inode first because it is fast
+                       if ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) {
+                               // mod-time and inode match an image in the shared cache, now check path
+                               const char* pathInCache = (char*)sSharedCache + p->pathFileOffset;
+                               bool cacheHit = (strcmp(path, pathInCache) == 0);
+                               if ( ! cacheHit ) {
+                                       // path does not match install name of dylib in cache, but inode and mtime does match
+                                       // perhaps path is a symlink to the cached dylib
+                                       struct stat pathInCacheStatBuf;
+                                       if ( stat(pathInCache, &pathInCacheStatBuf) != -1 )
+                                               cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf.st_dev) && (pathInCacheStatBuf.st_ino == stat_buf.st_ino) );        
+                               }
+                               if ( cacheHit ) {
+                                       // found image in cache, instantiate an ImageLoader with it
+                                       return new ImageLoaderMachO((struct mach_header*)(p->address), pathInCache, stat_buf, gLinkContext);
+                               }
+                       }
+               }       
+       }
+       return NULL;
+}
+#endif
+
+static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& context)
+{
+       // now sanity check that this loaded image does not have the same install path as any existing image
+       const char* loadedImageInstallPath = image->getInstallPath();
+       if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) {
+               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+                       ImageLoader* anImage = *it;
+                       const char* installPath = anImage->getInstallPath();
+                       if ( installPath != NULL) {
+                               if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
+                                       //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
+                                       delete image;
+                                       return anImage;
+                               }
+                       }
+               }
+       }
 
+       // some API's restrict what they can load
+       if ( context.mustBeBundle && !image->isBundle() )
+               throw "not a bundle";
+       if ( context.mustBeDylib && !image->isDylib() )
+               throw "not a dylib";
 
+       // 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);
+       
+       return image;
+}
 
 // map in file and instantiate an ImageLoader
 static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path, const LoadContext& context)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s)\n", __func__ , path);
        uint64_t fileOffset = 0;
        uint64_t fileLength = stat_buf.st_size;
-#if __ppc64__
-       if ( *((uint32_t*)((char*)(&stat_buf)+0x60)) == 0xFEFEFEFE )
-               fileLength = *((uint64_t*)((char*)(&stat_buf)+0x30));   // HACK work around for kernel stat bug rdar://problem/3845883
-#endif
 
        // validate it is a file (not directory)
        if ( (stat_buf.st_mode & S_IFMT) != S_IFREG ) 
                throw "not a file";
 
-       // min file is 4K
+       uint8_t firstPage[4096];
+       bool shortPage = false;
+       
+       // min mach-o file is 4K
        if ( fileLength < 4096 ) {
-               throw "file to short";
+               pread(fd, firstPage, fileLength, 0);
+               shortPage = true;
+       } 
+       else {
+               pread(fd, firstPage, 4096,0);
        }
        
-       uint8_t firstPage[4096];
-       pread(fd, firstPage, 4096,0);
-       
        // if fat wrapper, find usable sub-file
        const fat_header* fileStartAsFat = (fat_header*)firstPage;
        if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
@@ -1204,46 +1583,17 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
        
        // try mach-o loader
        if ( isCompatibleMachO(firstPage) ) {
-               char realFilePath[PATH_MAX];
-               if ( gLinkContext.slideAndPackDylibs ) {
-                       // when prebinding, we always want to track the real path of images
-                       if ( realpath(path, realFilePath) != NULL )
-                               path = realFilePath;
-               }
+               if ( shortPage ) 
+                       throw "file too short";
 
                // instantiate an image
                ImageLoader* image = new ImageLoaderMachO(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
                
-               // now sanity check that this loaded image does not have the same install path as any existing image
-               const char* loadedImageInstallPath = image->getInstallPath();
-               if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) {
-                       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-                               ImageLoader* anImage = *it;
-                               const char* installPath = anImage->getInstallPath();
-                               if ( installPath != NULL) {
-                                       if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
-                                               //fprintf(stderr, "duplicate(%s) => %p\n", installPath, anImage);
-                                               delete image;
-                                               return anImage;
-                                       }
-                               }
-                       }
-               }
-
-               // some API's restrict what they can load
-               if ( context.mustBeBundle && !image->isBundle() )
-                       throw "not a bundle";
-               if ( context.mustBeDylib && !image->isDylib() )
-                       throw "not a dylib";
-
-               // 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);
-
-               return image;
+               // validate
+               return checkandAddImage(image, context);
        }
        
-       // try other file formats...
+       // try other file formats here...
        
        
        // throw error about what was found
@@ -1263,40 +1613,50 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
 // try to open file
 static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stdout, "%s(%s)\n", __func__, path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 
-       // open file (automagically closed when this function exits)
-       FileOpener file(path);
-       
-       //fprintf(stderr, "open(%s) => %d\n", path, file.getFileDescriptor() );
-       
-       if ( file.getFileDescriptor() == -1 )
-               return NULL;
-               
+       // just return NULL if file not found, but record any other errors
        struct stat stat_buf;
-#if __ppc64__
-       memset(&stat_buf, 254, sizeof(struct stat));     // hack until rdar://problem/3845883 is fixed
-#endif
-       if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
-               throw "stat error";
+       if ( stat(path, &stat_buf) == -1 ) {
+               int err = errno;
+               if ( err != ENOENT ) {
+                       exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, err));
+               }
+               return NULL;
+       }
        
        // in case image was renamed or found via symlinks, check for inode match
        image = findLoadedImage(stat_buf);
        if ( image != NULL )
                return image;
        
-       // needed to implement NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
+       // do nothing if not already loaded and if RTLD_NOLOAD or NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
        if ( context.dontLoad )
                return NULL;
+
+#if DYLD_SHARED_CACHE_SUPPORT
+       // see if this image is in shared cache
+       image = findSharedCacheImage(stat_buf, path);
+       if ( image != NULL ) {
+               return checkandAddImage(image, context);
+       }
+#endif
        
+       // open file (automagically closed when this function exits)
+       FileOpener file(path);
+               
+       // just return NULL if file not found
+       if ( file.getFileDescriptor() == -1 ) 
+               return NULL;    
+
        try {
                return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
        }
        catch (const char* msg) {
-               char* newMsg = new char[strlen(msg) + strlen(path) + 8];
-               sprintf(newMsg, "%s: %s", path, msg);
+               const char* newMsg = dyld::mkstringf("%s: %s", path, msg);
                exceptions->push_back(newMsg);
+               free((void*)msg);
                return NULL;
        }
 }
@@ -1304,7 +1664,7 @@ static ImageLoader* loadPhase5open(const char* path, const LoadContext& context,
 // look for path match with existing loaded images
 static ImageLoader* loadPhase5check(const char* path, const LoadContext& context)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //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);
        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -1328,7 +1688,7 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
                }
        }
        
-       //fprintf(stderr, "check(%s) => NULL\n", path);
+       //dyld::log("%s(%s) => NULL\n", __func__,   path);
        return NULL;
 }
 
@@ -1336,7 +1696,7 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
 // open or check existing
 static ImageLoader* loadPhase5(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        if ( exceptions != NULL ) 
                return loadPhase5open(path, context, exceptions);
        else
@@ -1346,7 +1706,7 @@ static ImageLoader* loadPhase5(const char* path, const LoadContext& context, std
 // try with and without image suffix
 static ImageLoader* loadPhase4(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
        if (  gLinkContext.imageSuffix != NULL ) {
                char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2];
@@ -1358,13 +1718,21 @@ static ImageLoader* loadPhase4(const char* path, const LoadContext& context, std
        return image;
 }
 
+static ImageLoader* loadPhase2(const char* path, const LoadContext& context, 
+                                                          const char* const frameworkPaths[], const char* const libraryPaths[], 
+                                                          std::vector<const char*>* exceptions); // forward reference
+
 
 // expand @ variables
 static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        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);
+               }
                // handle @executable_path path prefix
                const char* executablePath = sExecPath;
                char newPath[strlen(executablePath) + strlen(path)];
@@ -1394,6 +1762,10 @@ 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);
+       
                // handle @loader_path path prefix
                char newPath[strlen(context.origin) + strlen(path)];
                strcpy(newPath, context.origin);
@@ -1421,6 +1793,38 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                return image;
                }
        }
+       else if ( context.implicitRPath || (strncmp(path, "@rpath/", 7) == 0) ) {
+               const char* trailingPath = (strncmp(path, "@rpath/", 7) == 0) ? &path[7] : path;
+               // substitute @rpath with all -rpath paths up the load chain
+               for(const ImageLoader::RPathChain* rp=context.rpath; rp != NULL; rp=rp->next) {
+                       if (rp->paths != NULL ) {
+                               for(std::vector<const char*>::iterator it=rp->paths->begin(); it != rp->paths->end(); ++it) {
+                                       const char* anRPath = *it;
+                                       char newPath[strlen(anRPath) + strlen(trailingPath)+2];
+                                       strcpy(newPath, anRPath);
+                                       strcat(newPath, "/"); 
+                                       strcat(newPath, trailingPath); 
+                                       image = loadPhase4(newPath, context, exceptions);
+                                       if ( image != NULL ) 
+                                               return image;
+                               }
+                       }
+               }
+               
+               // substitute @rpath with LD_LIBRARY_PATH
+               if ( sEnv.LD_LIBRARY_PATH != NULL ) {
+                       image = loadPhase2(trailingPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
+                       if ( image != NULL )
+                               return image;
+               }
+               
+               // if this is the "open" pass, don't try to open @rpath/... as a relative path
+               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);
+       }
        
        return loadPhase4(path, context, exceptions);
 }
@@ -1431,7 +1835,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
                                                           const char* const frameworkPaths[], const char* const libraryPaths[], 
                                                           std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
        const char* frameworkPartialPath = getFrameworkPartialPath(path);
        if ( frameworkPaths != NULL ) {
@@ -1442,7 +1846,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
                                strcpy(npath, *fp);
                                strcat(npath, "/");
                                strcat(npath, frameworkPartialPath);
-                               //fprintf(stderr, "dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
+                               //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
                                image = loadPhase4(npath, context, exceptions);
                                if ( image != NULL )
                                        return image;
@@ -1457,7 +1861,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
                        strcpy(libpath, *lp);
                        strcat(libpath, "/");
                        strcat(libpath, libraryLeafName);
-                       //fprintf(stderr, "dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
+                       //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
                        image = loadPhase4(libpath, context, exceptions);
                        if ( image != NULL )
                                return image;
@@ -1469,7 +1873,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
 // try search overrides and fallbacks
 static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 
        // handle LD_LIBRARY_PATH environment variables that force searching
@@ -1492,7 +1896,7 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
                return image;
        
        // try fallback paths during second time (will open file)
-       if ( (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_FALLBACK_LIBRARY_PATH != NULL)) ) {
+       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);
                if ( image != NULL )
                        return image;
@@ -1504,8 +1908,8 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
 // try root substitutions
 static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
-       
+       //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) {
@@ -1538,7 +1942,7 @@ static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std
 //
 ImageLoader* load(const char* path, const LoadContext& context)
 {
-       //fprintf(stderr, "%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s)\n", __func__ , path);
        char realPath[PATH_MAX];
        // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
        if ( context.useSearchPaths && ( gLinkContext.imageSuffix != NULL) ) {
@@ -1550,14 +1954,12 @@ ImageLoader* load(const char* path, const LoadContext& context)
        ImageLoader* image = loadPhase0(path, context, NULL);
        if ( image != NULL )
                return image;
-       
+
        // try all path permutations and try open() until first sucesss
        std::vector<const char*> exceptions;
        image = loadPhase0(path, context, &exceptions);
        if ( image != NULL )
                return image;
-       else if ( context.dontLoad )
-               return NULL;
        else if ( exceptions.size() == 0 )
                throw "image not found";
        else {
@@ -1571,6 +1973,7 @@ ImageLoader* load(const char* path, const LoadContext& context)
                for (unsigned int i=0; i < exceptions.size(); ++i) {
                        strcat(fullMsg, delim);
                        strcat(fullMsg, exceptions[i]);
+                       free((void*)exceptions[i]);
                }
                throw (const char*)fullMsg;
        }
@@ -1579,6 +1982,219 @@ ImageLoader* load(const char* path, const LoadContext& context)
 
 
 
+#if DYLD_SHARED_CACHE_SUPPORT
+
+
+// hack until dyld no longer needs to run on Leopard kernels that don't have new shared region syscall
+static bool newSharedRegionSyscallAvailable()
+{
+       int shreg_version;
+       size_t buffer_size = sizeof(shreg_version);
+       if ( sysctlbyname("vm.shared_region_version", &shreg_version, &buffer_size, NULL, 0) == 0 ) {
+          if ( shreg_version == 3 ) 
+                       return true;
+       }
+       return false;
+}
+
+
+static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_address)
+{
+       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) && newSharedRegionSyscallAvailable() ) 
+               return syscall(294, start_address);
+       return -1;
+}
+
+
+static int __attribute__((noinline)) _shared_region_map_np(int fd, uint32_t count, const shared_file_mapping_np mappings[])
+{
+       int result;
+       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) && newSharedRegionSyscallAvailable() ) {
+               return syscall(295, fd, count, mappings);
+       }
+
+       // 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
+       
+       // map cache just for this process with mmap()
+       bool failed = false;
+       const shared_file_mapping_np* start = mappings;
+       const shared_file_mapping_np* end = &mappings[count];
+       for (const shared_file_mapping_np* p = start; p < end; ++p ) {
+               void* mmapAddress = (void*)(uintptr_t)(p->sfm_address);
+               size_t size = p->sfm_size;
+               int protection = 0;
+               if ( p->sfm_init_prot & VM_PROT_EXECUTE )
+                       protection   |= PROT_EXEC;
+               if ( p->sfm_init_prot & VM_PROT_READ )
+                       protection   |= PROT_READ;
+               if ( p->sfm_init_prot & VM_PROT_WRITE )
+                       protection   |= PROT_WRITE;
+               off_t offset = p->sfm_file_offset;
+               mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
+               if ( mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset) != mmapAddress )
+                       failed = true;
+       }
+       if ( !failed ) {
+               result = 0;
+               gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
+       }
+       else {
+               result = -1;
+               gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
+               if ( gLinkContext.verboseMapping ) 
+                       dyld::log("dyld: shared cached cannot be mapped\n");
+       }
+
+       return result;
+}
+
+
+
+#if __ppc__
+       #define ARCH_NAME                       "ppc"
+       #define ARCH_NAME_ROSETTA       "rosetta"
+       #define ARCH_VALUE                      CPU_TYPE_POWERPC
+       #define ARCH_CACHE_MAGIC        "dyld_v1     ppc"
+#elif __ppc64__
+       #define ARCH_NAME                       "ppc64"
+       #define ARCH_VALUE                      CPU_TYPE_POWERPC64
+       #define ARCH_CACHE_MAGIC        "dyld_v1   ppc64"
+#elif __i386__
+       #define ARCH_NAME                       "i386"
+       #define ARCH_VALUE                      CPU_TYPE_I386
+       #define ARCH_CACHE_MAGIC        "dyld_v1    i386"
+#elif __x86_64__
+       #define ARCH_NAME                       "x86_64"
+       #define ARCH_VALUE                      CPU_TYPE_X86_64
+       #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64"
+#endif
+
+
+static void mapSharedCache()
+{      
+       uint64_t cacheBaseAddress;
+       // quick check if a cache is alreay mapped into shared region
+       if ( _shared_region_check_np(&cacheBaseAddress) == 0 ) {
+               sSharedCache = (dyld_cache_header*)cacheBaseAddress;
+               // if we don't understand the currently mapped shared cache, then ignore
+               if ( strcmp(sSharedCache->magic, ARCH_CACHE_MAGIC) != 0 ) {
+                       sSharedCache = NULL;
+                       if ( gLinkContext.verboseMapping ) 
+                               dyld::log("dyld: existing shared cached in memory is not compatible\n");
+               }
+       }
+       else {
+               // map in shared cache to shared region
+               int fd;
+#if __ppc__
+               // rosetta cannot handle optimized _ppc cache, so it use _rosetta cache instead, rdar://problem/5495438
+               if ( isRosetta() )
+                       fd = open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_ROSETTA, O_RDONLY);
+               else
+#endif
+               fd = open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, O_RDONLY);
+               if ( fd != -1 ) {
+                       uint8_t firstPage[4096];
+                       if ( ::read(fd, firstPage, 4096) == 4096 ) {
+                               dyld_cache_header* header = (dyld_cache_header*)firstPage;
+                               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* const end = &mappings[header->mappingCount];
+                                       // validate that the cache file has not been truncated
+                                       bool goodCache = false;
+                                       struct stat stat_buf;
+                                       if ( fstat(fd, &stat_buf) == 0 ) {
+                                               goodCache = true;
+                                               for (const shared_file_mapping_np* p = mappings; p < end; ++p) {
+                                                       if ( p->sfm_file_offset+p->sfm_size > (uint64_t)stat_buf.st_size )
+                                                               goodCache = false;
+                                               }
+                                       }
+                                       if ( goodCache ) {
+                                               const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPage[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");
+               }
+       }
+       
+       // remember if dyld loaded at same address as when cache built
+       if ( sSharedCache != NULL ) {
+               gLinkContext.dyldLoadedAtSameAddressNeededBySharedCache = ((uintptr_t)(sSharedCache->dyldBaseAddress) == (uintptr_t)&_mh_dylinker_header);
+       }
+       
+       // tell gdb where the shared cache is
+       if ( sSharedCache != NULL ) {
+               const shared_file_mapping_np* const start = (shared_file_mapping_np*)((uint8_t*)sSharedCache + sSharedCache->mappingOffset);
+               dyld_shared_cache_ranges.sharedRegionsCount = sSharedCache->mappingCount;
+               // only room to tell gdb about first four regions
+               if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
+                       dyld_shared_cache_ranges.sharedRegionsCount = 4;
+               if ( gLinkContext.verboseMapping ) {
+                       if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
+                               dyld::log("dyld: Mapping shared cache\n");
+                       else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
+                               dyld::log("dyld: Mapping private shared cache\n");
+               }
+               const shared_file_mapping_np* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
+               int index = 0;
+               for (const shared_file_mapping_np* p = start; p < end; ++p, ++index ) {
+                       dyld_shared_cache_ranges.ranges[index].start = p->sfm_address;
+                       dyld_shared_cache_ranges.ranges[index].length = p->sfm_size;
+                       if ( gLinkContext.verboseMapping ) {
+                               dyld::log("        0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n", p->sfm_address, p->sfm_address+p->sfm_size-1,
+                                       ((p->sfm_init_prot & VM_PROT_READ) ? "read " : ""),
+                                       ((p->sfm_init_prot & VM_PROT_WRITE) ? "write " : ""),
+                                       ((p->sfm_init_prot & VM_PROT_EXECUTE) ? "execute " : ""),  p->sfm_init_prot, p->sfm_max_prot);
+                       }
+               #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 ( (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);
+                       }
+               #endif
+               }
+
+       }
+}
+#endif // #if DYLD_SHARED_CACHE_SUPPORT
+
+
+
 // create when NSLinkModule is called for a second time on a bundle
 ImageLoader* cloneImage(ImageLoader* image)
 {
@@ -1588,9 +2204,6 @@ ImageLoader* cloneImage(ImageLoader* image)
        FileOpener file(image->getPath());
        
        struct stat stat_buf;
-#if __ppc64__
-       memset(&stat_buf, 254, sizeof(struct stat));     // hack until rdar://problem/3845883 is fixed
-#endif
        if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
                throw "stat error";
        
@@ -1631,7 +2244,7 @@ ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* module
                }
        }
 
-       // try mach-o each loader
+       // try each loader
        if ( isCompatibleMachO(mem) ) {
                ImageLoader* image = new ImageLoaderMachO(moduleName, (mach_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
@@ -1640,7 +2253,7 @@ ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* module
                return image;
        }
        
-       // try other file formats...
+       // try other file formats here...
        
        // throw error about what was found
        switch (*(uint32_t*)mem) {
@@ -1661,17 +2274,12 @@ void registerAddCallback(ImageCallback func)
        // now add to list to get notified when any more images are added
        sAddImageCallbacks.push_back(func);
        
-       // call callback with all existing images, starting at roots
-       const int rootCount = sImageRoots.size();
-       for(int i=0; i < rootCount; ++i) {
-               ImageLoader* image = sImageRoots[i];
-               image->runNotification(gLinkContext, sAddImageCallbacks.size());
+       // call callback with all existing images
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+               ImageLoader* image = *it;
+               if ( image->getState() >= dyld_image_state_bound && image->getState() < dyld_image_state_terminated )
+                       (*func)(image->machHeader(), image->getSlide());
        }
-       
-//     for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
-//             ImageLoader* image = *it;
-//             image->runNotification(gLinkContext, sAddImageCallbacks.size());
-//     }
 }
 
 void registerRemoveCallback(ImageCallback func)
@@ -1696,21 +2304,14 @@ const char* getErrorMessage()
        return error_string;
 }
 
+
 void  halt(const char* message)
 {
-       fprintf(stderr, "dyld: %s\n", message);
+       dyld::log("dyld: %s\n", message);
        setErrorMessage(message);
        strncpy(error_string, message, sizeof(error_string)-1);
        error_string[sizeof(error_string)-1] = '\0';
-       
-#if __ppc__ || __ppc64__
-       __asm__  ("trap");
-#elif __i386__ || __x86_64__
-       __asm__  ("int3");
-#else
-       #error unknown architecture
-#endif
-       abort();        // needed to suppress warning that noreturn function returns
+       dyld_fatal_error(error_string);
 }
 
 
@@ -1719,8 +2320,8 @@ uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
        uintptr_t result = 0;
        // acquire read-lock on dyld's data structures
 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
-       if ( gThreadHelpers != NULL ) 
-               (*gThreadHelpers->lockForReading)();
+       if ( gLibSystemHelpers != NULL ) 
+               (*gLibSystemHelpers->lockForReading)();
 #endif
        // lookup and bind lazy pointer and get target address
        try {
@@ -1736,17 +2337,17 @@ uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
                target = dyld::findImageByMachHeader(mh);
        #endif
                if ( target == NULL )
-                       throw "image not found for lazy pointer";
+                       throwf("image not found for lazy pointer at %p", lazyPointer);
                result = target->doBindLazySymbol(lazyPointer, gLinkContext);
        }
        catch (const char* message) {
-               fprintf(stderr, "dyld: lazy symbol binding failed: %s\n", message);
+               dyld::log("dyld: lazy symbol binding failed: %s\n", message);
                halt(message);
        }
        // release read-lock on dyld's data structures
 #if 0
-       if ( gThreadHelpers != NULL ) 
-               (*gThreadHelpers->unlockForReading)();
+       if ( gLibSystemHelpers != NULL ) 
+               (*gLibSystemHelpers->unlockForReading)();
 #endif
        // return target address to glue which jumps to it with real parameters restored
        return result;
@@ -1772,7 +2373,7 @@ static void undefinedHandler(const char* symboName)
        }
 }
 
-static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, ImageLoader** image)
+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 ) {
@@ -1789,10 +2390,15 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
                        return false;
                if ( zlImage != NULL ) {
                        // ZeroLink cache knows where the symbol is
-                       *sym = zlImage->findExportedSymbol(name, NULL, false, image);
-                       if ( *sym != NULL ) {
-                               *image = zlImage;
-                               return true;
+                       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 {
@@ -1801,7 +2407,7 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
                        for(unsigned int i=0; i < imageCount; ++i){
                                ImageLoader* anImage = sAllImages[i];
                                if ( anImage->isBundle() && !anImage->hasHiddenExports() ) {
-                                       //fprintf(stderr, "dyld: search for %s in %s\n", name, anImage->getPath());
+                                       //dyld::log("dyld: search for %s in %s\n", name, anImage->getPath());
                                        *sym = anImage->findExportedSymbol(name, NULL, false, image);
                                        if ( *sym != NULL ) {
                                                return true;
@@ -1812,11 +2418,19 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
        }
 
        // search all images in order
-       ImageLoader* firstWeakImage = NULL;
+       const ImageLoader* firstWeakImage = NULL;
        const ImageLoader::Symbol* firstWeakSym = NULL;
        const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i){
+       for(unsigned int i=0; i < imageCount; ++i) {
                ImageLoader* anImage = sAllImages[i];
+               // the use of inserted libraries alters search order
+               // so that inserted libraries are found before the main executable
+               if ( sInsertedDylibCount > 0 ) {
+                       if ( i < sInsertedDylibCount )
+                               anImage = sAllImages[i+1];
+                       else if ( i == sInsertedDylibCount )
+                               anImage = sAllImages[0];
+               }
                if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) {
                        *sym = anImage->findExportedSymbol(name, NULL, false, image);
                        if ( *sym != NULL ) {
@@ -1844,18 +2458,18 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
        return false;
 }
 
-bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image)
+bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
        return findExportedSymbol(name, false, sym, image);
 }
 
-bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image)
+bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
        return findExportedSymbol(name, true, sym, image);
 }
 
 
-bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, ImageLoader** image)
+bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
        // search all images in order
        const unsigned int imageCount = sAllImages.size();
@@ -1872,52 +2486,137 @@ bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstri
        return false;
 }
 
-static void getMappedRegions(ImageLoader::RegionsVector& regions)
+static ImageLoader::MappedRegion* getMappedRegions(ImageLoader::MappedRegion* regions)
 {
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i){
-               ImageLoader* anImage = sAllImages[i];
-               anImage->addMappedRegions(regions);
+       ImageLoader::MappedRegion* end = regions;
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+               (*it)->getMappedRegions(end);
+       }
+       return end;
+}
+
+void registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
+{
+       // mark the image that the handler is in as never-unload because dyld has a reference into it
+       ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
+       if ( handlerImage != NULL )
+               handlerImage->setNeverUnload();
+
+       // add to list of handlers
+       std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
+       if ( handlers != NULL ) {
+               handlers->push_back(handler);
+
+               // call callback with all existing images
+               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+                       ImageLoader* image = *it;
+                       dyld_image_info  info;
+                       info.imageLoadAddress   = image->machHeader();
+                       info.imageFilePath              = image->getPath();
+                       info.imageFileModDate   = image->lastModified();
+                       // should only call handler if state == image->state
+                       if ( image->getState() == state )
+                               (*handler)(state, 1, &info);
+                       // ignore returned string, too late to do anything
+               }
        }
 }
 
+void registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
+{
+       // mark the image that the handler is in as never-unload because dyld has a reference into it
+       ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
+       if ( handlerImage != NULL )
+               handlerImage->setNeverUnload();
+
+       // add to list of handlers
+       std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
+       if ( handlers != NULL ) {
+               // insert at front, so that gdb handler is always last
+               handlers->insert(handlers->begin(), handler);
+               
+               // call callback with all existing images
+               try {
+                       notifyBatchPartial(state, true, handler);
+               }
+               catch (const char* msg) {
+                       // ignore request to abort during registration
+               }
+       }
+}
 
-static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const char* rpath[])
+static ImageLoader* libraryLocator(const char* libraryName, bool search, bool findDLL, const char* origin, const ImageLoader::RPathChain* rpaths)
 {
        dyld::LoadContext context;
        context.useSearchPaths          = search;
        context.useLdLibraryPath        = false;
+       context.implicitRPath           = false;
+       context.matchByInstallName      = false;
        context.dontLoad                        = false;
        context.mustBeBundle            = false;
        context.mustBeDylib                     = true;
-       context.matchByInstallName      = false;
+       context.findDLL                         = findDLL;
        context.origin                          = origin;
-       context.rpath                           = rpath;
+       context.rpath                           = rpaths;
        return load(libraryName, context);
 }
 
-       
-static void setContext(int argc, const char* argv[], const char* envp[], const char* apple[])
+static const char* basename(const char* path)
+{
+    const char* last = path;
+    for (const char* s = path; *s != '\0'; s++) {
+        if (*s == '/') 
+                       last = s+1;
+    }
+    return last;
+}
+
+static void setContext(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
 {
        gLinkContext.loadLibrary                        = &libraryLocator;
-       gLinkContext.imageNotification          = &imageNotification;
        gLinkContext.terminationRecorder        = &terminationRecorder;
        gLinkContext.flatExportFinder           = &flatFindExportedSymbol;
        gLinkContext.coalescedExportFinder      = &findCoalescedExportedSymbol;
        gLinkContext.undefinedHandler           = &undefinedHandler;
+#if IMAGE_NOTIFY_SUPPORT
        gLinkContext.addImageNeedingNotification = &addImageNeedingNotification;
        gLinkContext.notifyAdding                       = &notifyAdding;
+#endif
        gLinkContext.getAllMappedRegions        = &getMappedRegions;
        gLinkContext.bindingHandler                     = NULL;
+       gLinkContext.notifySingle                       = &notifySingle;
+       gLinkContext.notifyBatch                        = &notifyBatch;
+       gLinkContext.removeImage                        = &removeImage;
+       gLinkContext.registerDOFs                       = &registerDOFs;
+       gLinkContext.clearAllDepths                     = &clearAllDepths;
+       gLinkContext.imageCount                         = &imageCount;
+       gLinkContext.notifySharedCacheInvalid= &notifySharedCacheInvalid;
+#if __i386__
+       gLinkContext.makeSharedCacheImportSegmentsWritable = &makeSharedCacheImportSegmentsWritable;
+#endif
+       gLinkContext.setNewProgramVars          = &setNewProgramVars;
+#if SUPPORT_OLD_CRT_INITIALIZATION
+       gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
+#endif
        gLinkContext.bindingOptions                     = ImageLoader::kBindingNone;
-       gLinkContext.mainExecutable                     = sMainExecutable;
        gLinkContext.argc                                       = argc;
        gLinkContext.argv                                       = argv;
        gLinkContext.envp                                       = envp;
        gLinkContext.apple                                      = apple;
+       gLinkContext.progname                           = (argv[0] != NULL) ? basename(argv[0]) : "";
+       gLinkContext.programVars.mh                     = mainExecutableMH;
+       gLinkContext.programVars.NXArgcPtr      = &gLinkContext.argc;
+       gLinkContext.programVars.NXArgvPtr      = &gLinkContext.argv;
+       gLinkContext.programVars.environPtr     = &gLinkContext.envp;
+       gLinkContext.programVars.__prognamePtr=&gLinkContext.progname;
+       gLinkContext.mainExecutable                     = NULL;
+       gLinkContext.imageSuffix                        = NULL;
+       gLinkContext.prebindUsage                       = ImageLoader::kUseAllPrebinding;
+       gLinkContext.sharedRegionMode           = ImageLoader::kUseSharedRegion;
 }
 
-static bool isRosetta()
+#if __ppc__ || __i386__
+bool isRosetta()
 {
        int mib[] = { CTL_KERN, KERN_CLASSIC, getpid() };
        int is_classic = 0;
@@ -1929,11 +2628,26 @@ static bool isRosetta()
        }
        return false;
 }
+#endif
+
+#if 0
+static void printAllImages()
+{
+       dyld::log("printAllImages()\n");
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+               ImageLoader* image = *it;
+               dyld_image_states imageState = image->getState();
+               dyld::log("  state=%d, refcount=%d, name=%s\n", imageState, image->referenceCount(), image->getShortName());
+               image->printReferenceCounts();
+       }
+}
+#endif
+
 
-void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader::InitializerRunning runInitializers)
+void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChain& loaderRPaths)
 {
        // add to list of known images.  This did not happen at creation time for bundles
-       if ( image->isBundle() )
+       if ( image->isBundle() && !image->isLinked() )
                addImage(image);
 
        // we detect root images as those not linked in yet 
@@ -1951,11 +2665,11 @@ void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader
 
        // process images
        try {
-               image->link(gLinkContext, bindness, runInitializers, sAddImageCallbacks.size());
+               image->link(gLinkContext, forceLazysBound, false, loaderRPaths);
        }
        catch (const char* msg) {
-               sAllImagesMightContainUnlinkedImages = true;
-               throw msg;
+               garbageCollectImages();
+               throw;
        }
        
 #if OLD_GDB_DYLD_INTERFACE
@@ -1965,16 +2679,86 @@ void link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader
 }
 
 
-//
-// _pthread_keys is partitioned in a lower part that dyld will use; libSystem
-// will use the upper part.  We set __pthread_tsd_first to 1 as the start of
-// the lower part.  Libc will take #1 and c++ exceptions will take #2.  There
-// is one free key=3 left.
-//
-extern "C" {
-       extern int __pthread_tsd_first;
+void runInitializers(ImageLoader* image)
+{
+       // do bottom up initialization
+       image->runInitializers(gLinkContext);
+}
+
+void garbageCollectImages()
+{
+       // keep scanning list of images until entire list is scanned with no unreferenced images
+       bool mightBeUnreferencedImages = true;
+       while ( mightBeUnreferencedImages ) {
+               mightBeUnreferencedImages = false;
+               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+                       ImageLoader* image = *it;
+                       if ( (image->referenceCount() == 0) && !image->neverUnload() && !image->isBeingRemoved() ) {
+                               try {
+                                       //dyld::log("garbageCollectImages: deleting %s\n", image->getPath());
+                                       image->setBeingRemoved();
+                                       removeImage(image);
+                                       delete image;
+                               }
+                               catch (const char* msg) {
+                                       dyld::warn("problem deleting image: %s\n", msg);
+                               }
+                               mightBeUnreferencedImages = true;
+                               break;
+                       }
+               }
+       }
+       //printAllImages();
+}
+
+
+static void preflight_finally(ImageLoader* image)
+{
+       if ( image->isBundle() ) {
+               removeImageFromAllImages(image->machHeader());
+               delete image;
+       }
+       sBundleBeingLoaded = NULL;
+       dyld::garbageCollectImages();
+}
+
+
+void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths)
+{
+       try {
+               if ( image->isBundle() ) 
+                       sBundleBeingLoaded = image;     // hack
+               image->link(gLinkContext, false, true, loaderRPaths);
+       }
+       catch (const char* msg) {       
+               preflight_finally(image);
+               throw;
+       }
+       preflight_finally(image);
+}
+
+static void loadInsertedDylib(const char* path)
+{
+       ImageLoader* image = NULL;
+       try {
+               LoadContext context;
+               context.useSearchPaths          = false;
+               context.useLdLibraryPath        = false;
+               context.implicitRPath           = false;
+               context.matchByInstallName      = false;
+               context.dontLoad                        = false;
+               context.mustBeBundle            = false;
+               context.mustBeDylib                     = true;
+               context.findDLL                         = false;
+               context.origin                          = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
+               context.rpath                           = NULL;
+               image = load(path, context);
+               image->setNeverUnload();
+       }
+       catch (...) {
+               halt(dyld::mkstringf("could not load inserted library: %s\n", path));
+       }
 }
 
 //
 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which
@@ -1983,10 +2767,9 @@ extern "C" {
 // Returns address of main() in target program which __dyld_start jumps to
 //
 uintptr_t
-_main(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
+_main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
 {      
-       // set pthread keys to dyld range
-       __pthread_tsd_first = 1;
+       setContext(mainExecutableMH, argc, argv, envp, apple);
        
        // Pickup the pointer to the exec path.
        sExecPath = apple[0];
@@ -1998,7 +2781,6 @@ _main(const struct mach_header* mainExecutableMH, int argc, const char* argv[],
                // we want any i386 dylibs (e.g. any used by Rosetta) to not load in the shared region
                // because the shared region is being used by ppc dylibs
                gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
-               sExecPath = strdup(apple[0] + strlen(apple[0]) + 1);
                ignoreEnvironmentVariables = true;
        }
 #endif
@@ -2016,7 +2798,8 @@ _main(const struct mach_header* mainExecutableMH, int argc, const char* argv[],
        }
        uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
-       if ( issetugid() )
+       sMainExecutableIsSetuid = issetugid();
+       if ( sMainExecutableIsSetuid )
                pruneEnvironmentVariables(envp, &apple);
        else
                checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
@@ -2025,75 +2808,69 @@ _main(const struct mach_header* mainExecutableMH, int argc, const char* argv[],
        if ( sEnv.DYLD_PRINT_ENV ) 
                printEnvironmentVariables(envp);
        getHostInfo();
-       setContext(argc, argv, envp, apple);
-       ImageLoader::BindingLaziness bindness = sEnv.DYLD_BIND_AT_LAUNCH ? ImageLoader::kLazyAndNonLazy : ImageLoader::kNonLazyOnly;
+       // 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);
+       sImageRoots.reserve(16);
+       sAddImageCallbacks.reserve(4);
+       sRemoveImageCallbacks.reserve(4);
+       sImageFilesNeedingTermination.reserve(16);
+       sImageFilesNeedingDOFUnregistration.reserve(8);
        
-       // load any inserted libraries before loading the main executable so that they are first in flat namespace
-       int insertLibrariesCount = 0;
-       if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
-               for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) {
-                       insertLibrariesCount++;
-               }
-       }
-       ImageLoader* insertedImages[insertLibrariesCount];
-       if ( insertLibrariesCount > 0 ) {
-               for (int i=0; i < insertLibrariesCount; ++i) {
-                       try {
-                               LoadContext context;
-                               context.useSearchPaths          = false;
-                               context.useLdLibraryPath        = false;
-                               context.dontLoad                        = false;
-                               context.mustBeBundle            = false;
-                               context.mustBeDylib                     = true;
-                               context.matchByInstallName      = false;
-                               context.origin                          = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
-                               context.rpath                           = NULL;
-                               insertedImages[i] = load(sEnv.DYLD_INSERT_LIBRARIES[i], context);
-                       }
-                       catch (...) {
-                               char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50];
-                               sprintf(buf, "could not load inserted library: %s\n", sEnv.DYLD_INSERT_LIBRARIES[i]);
-                               insertedImages[i]  = NULL;
-                               halt(buf);
-                       }
-               }
-       }
-       
-       // load and link main executable
        try {
-               sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, sExecPath);
+               // instantiate ImageLoader for main executable
+               sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
+               sMainExecutable->setNeverUnload();
                gLinkContext.mainExecutable = sMainExecutable;
+               // load shared cache
+               checkSharedRegionDisable();
+       #if DYLD_SHARED_CACHE_SUPPORT
+               if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion )
+                       mapSharedCache();
+       #endif
+               // load any inserted libraries
+               if      ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
+                       for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) 
+                               loadInsertedDylib(*lib);
+               }
+               // record count of inserted libraries so that a flat search will look at 
+               // inserted libraries, then main, then others.
+               sInsertedDylibCount = sAllImages.size()-1;
+
+               // link main executable
+               gLinkContext.linkingMainExecutable = true;
+               link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
+               gLinkContext.linkingMainExecutable = false;
                if ( sMainExecutable->forceFlat() ) {
                        gLinkContext.bindFlat = true;
                        gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
                }
-               link(sMainExecutable, bindness, ImageLoader::kDontRunInitializers);
                result = (uintptr_t)sMainExecutable->getMain();
+
+               // link any inserted libraries
+               // do this after linking main executable so that any dylibs pulled in by inserted 
+               // dylibs (e.g. libSystem) will not be in front of dylibs the program uses
+               if ( sInsertedDylibCount > 0 ) {
+                       for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
+                               ImageLoader* image = sAllImages[i+1];
+                               link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
+                       }
+               }
+               
+       #if SUPPORT_OLD_CRT_INITIALIZATION
+               // Old way is to run initializers via a callback from crt1.o
+               if ( ! gRunInitializersOldWay ) 
+       #endif
+               initializeMainExecutable(); // run all initializers
        }
        catch(const char* message) {
                halt(message);
        }
        catch(...) {
-               fprintf(stderr, "dyld: launch failed\n");
+               dyld::log("dyld: launch failed\n");
        }
-       
 
-       // Link in any inserted libraries.  
-       // Do this after linking main executable so any extra libraries pulled in by inserted libraries are at end of flat namespace
-       if ( insertLibrariesCount > 0 ) {
-               for (int i=0; i < insertLibrariesCount; ++i) {
-                       try {
-                               if ( insertedImages[i] != NULL )
-                                       link(insertedImages[i], bindness, ImageLoader::kDontRunInitializers);
-                       }
-                       catch (const char* message) {
-                               char buf[strlen(sEnv.DYLD_INSERT_LIBRARIES[i])+50+strlen(message)];
-                               sprintf(buf, "could not link inserted library: %s\n%s\n", sEnv.DYLD_INSERT_LIBRARIES[i], message);
-                               halt(buf);
-                       }
-               }
-       }
-       
        return result;
 }
 
index ee6ad95799b58d2a6360b7c386d2665f6f3cfd86..44127472fbd1049e71baa541e03f353b39c53b64 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
+#  Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
 # 
 #  @APPLE_LICENSE_HEADER_START@
 #  
 
 # 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
index 72e0e2afaa728f0ae02b3cb9ae186e26b85ebf34..4ccbdd7db887895ea9f6abded52bd84e78c92aa0 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-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,6 +25,7 @@
 #include <stdint.h>
 
 #include "ImageLoader.h"
+#include "mach-o/dyld_priv.h"
 
 
 
@@ -38,12 +39,14 @@ namespace dyld {
        {
                bool                    useSearchPaths;
                bool                    useLdLibraryPath;
+               bool                    implicitRPath;
                bool                    matchByInstallName;
                bool                    dontLoad;
                bool                    mustBeBundle;
                bool                    mustBeDylib;
-               const char*             origin;                 // path for expanding @loader_path
-               const char**    rpath;                  // future support of -rpath
+               bool                    findDLL;
+               const char*                                             origin;                 // path for expanding @loader_path
+               const ImageLoader::RPathChain*  rpath;                  // paths for expanding @rpath
        };
 
 
@@ -52,36 +55,43 @@ namespace dyld {
        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 const struct ThreadingHelpers*   gThreadHelpers;
-
-       
+       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                                     link(ImageLoader* image, ImageLoader::BindingLaziness bindness, ImageLoader::InitializerRunning runInitializers);
-       extern void                                     runTerminators();
+       extern void                                     preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths);
+       extern void                                     link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChain& loaderRPaths);
+       extern void                                     runInitializers(ImageLoader* image);
+       extern void                                     runTerminators(void*);
        extern const char*                      getExecutablePath();
-       extern bool                                     validImage(ImageLoader*);
+       extern bool                                     validImage(const ImageLoader*);
        extern ImageLoader*                     getIndexedImage(uint32_t index);
        extern uint32_t                         getImageCount();
        extern ImageLoader*                     findImageByMachHeader(const struct mach_header* target);
        extern ImageLoader*                     findImageContainingAddress(const void* addr);
        extern ImageLoader*                     findImageByName(const char* path);
        extern ImageLoader*                     findLoadedImageByInstallPath(const char* path);
-       extern bool                                     flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, ImageLoader** image);
-       extern bool                                     flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, ImageLoader** image);
+       extern bool                                     flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image);
+       extern bool                                     flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image);
        extern ImageLoader*                     load(const char* path, const LoadContext& context);
        extern ImageLoader*                     loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName);
        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, int argc, const char* argv[], const char* envp[], const char* apple[]);
+       extern uintptr_t                        _main(const struct mach_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();
@@ -89,6 +99,9 @@ namespace dyld {
        extern bool                                     mainExecutablePrebound();
        extern ImageLoader*                     mainExecutable();
        extern void                                     processDyldEnvironmentVarible(const char* key, const char* value);
+       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();
 
 };
 
index 81842233630211eb0004018033daf72cdabf375d..1c2a03188f0fdea984e4434b2cd2a6d2fbfcf049 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#  Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
 # 
 #  @APPLE_LICENSE_HEADER_START@
 #  
 
 # 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
index 06d9defccff3df2918203c58890dff8c6d60a819..6daf5f10109dfccb4fcd31261c1a8f67666f1bc5 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-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 //
 //
 
-
+#define __STDC_LIMIT_MACROS
 #include <stddef.h>
-#include <stdio.h>
+#include <stdint.h>
 #include <string.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+
+#include <vector>
+#include <map>
+#include <algorithm>
+
 #include <mach/mach.h>
 #include <sys/time.h>
 #include <sys/sysctl.h>
 
 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_gdb.h"
+#include "mach-o/dyld_images.h"
 #include "mach-o/dyld.h"
 #include "mach-o/dyld_priv.h"
-#include "dlfcn.h"
+#include "mach-o/dyld-update-prebinding.h"
 
 #include "ImageLoader.h"
 #include "dyld.h"
-#include "dyldLibSystemThreadHelpers.h"
+#include "dyldLibSystemInterface.h"
+
+#undef _POSIX_C_SOURCE
+#include "dlfcn.h"
+
+
+#ifndef RTLD_DLL
+       #define RTLD_DLL        0x200   /* Mac OS X 10.5 and later */
+#endif
 
 static char sLastErrorFilePath[1024];
 static NSLinkEditErrors sLastErrorFileCode;
@@ -54,24 +70,21 @@ static int sLastErrorNo;
 // 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
 // This conditional keeps support for old libSystem's which needed some help implementing the API's
-#define OLD_LIBSYSTEM_SUPPORT 1
+#define OLD_LIBSYSTEM_SUPPORT (__ppc__ || __i386__)
 
 
 // The following functions have no prototype in any header.  They are special cases
 // where _dyld_func_lookup() is used directly.
 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_prepare();
-static void _dyld_fork_parent();
 static void _dyld_fork_child();
-static void _dyld_fork_child_final();
 static void _dyld_make_delayed_module_initializer_calls();
-static void _dyld_mod_term_funcs();
 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::ThreadingHelpers*);
-static void _dyld_update_prebinding(int pathCount, const char* paths[], uint32_t flags);
+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
@@ -91,38 +104,37 @@ struct dyld_func {
 };
 
 static struct dyld_func dyld_funcs[] = {
-    {"__dyld_image_count",                                                     (void*)_dyld_image_count },
-    {"__dyld_get_image_header",                                                (void*)_dyld_get_image_header },
-    {"__dyld_get_image_vmaddr_slide",                          (void*)_dyld_get_image_vmaddr_slide },
-    {"__dyld_get_image_name",                                          (void*)_dyld_get_image_name },
+       {"__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 },
+    {"__dyld_dlopen",                                                                  (void*)dlopen },
+    {"__dyld_dlsym",                                                                   (void*)dlsym },
+    {"__dyld_dlopen_preflight",                                                        (void*)dlopen_preflight },
+    {"__dyld_get_image_header_containing_address",             (void*)_dyld_get_image_header_containing_address },
+       {"__dyld_image_count",                                                          (void*)_dyld_image_count },
+    {"__dyld_get_image_header",                                                        (void*)_dyld_get_image_header },
+    {"__dyld_get_image_vmaddr_slide",                                  (void*)_dyld_get_image_vmaddr_slide },
+    {"__dyld_get_image_name",                                                  (void*)_dyld_get_image_name },
+    {"__dyld__NSGetExecutablePath",                                            (void*)_NSGetExecutablePath },
+       
+       // the rest of these are either deprecated or SPIs
     {"__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_objc",                                    (void*)unimplemented },
     {"__dyld_lookup_and_bind_fully",                           (void*)_dyld_lookup_and_bind_fully },
     {"__dyld_install_handlers",                                                (void*)_dyld_install_handlers },
     {"__dyld_link_edit_error",                                         (void*)NSLinkEditError },
-#if OLD_LIBSYSTEM_SUPPORT
-    {"__dyld_link_module",                                                     (void*)_dyld_link_module },
-#endif
     {"__dyld_unlink_module",                                           (void*)NSUnLinkModule },
-    {"__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_register_func_for_link_module",           (void*)unimplemented },
-    {"__dyld_register_func_for_unlink_module",         (void*)unimplemented },
-    {"__dyld_register_func_for_replace_module",                (void*)unimplemented },
-    {"__dyld_get_objc_module_sect_for_module",         (void*)unimplemented },
     {"__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_get_image_header_containing_address",  (void*)_dyld_get_image_header_containing_address },
     {"__dyld_moninit",                                                         (void*)_dyld_moninit },
-    {"__dyld_register_binding_handler",                                                (void*)_dyld_register_binding_handler },
-    {"__dyld_fork_prepare",                                                    (void*)_dyld_fork_prepare },
-    {"__dyld_fork_parent",                                                     (void*)_dyld_fork_parent },
-    {"__dyld_fork_child",                                                      (void*)_dyld_fork_child },
-    {"__dyld_fork_child_final",                                                (void*)_dyld_fork_child_final },
-    {"__dyld_fork_mach_init",                                          (void*)unimplemented },
-    {"__dyld_make_delayed_module_initializer_calls",(void*)_dyld_make_delayed_module_initializer_calls },
+    {"__dyld_register_binding_handler",                                (void*)_dyld_register_binding_handler },
     {"__dyld_NSNameOfSymbol",                                          (void*)NSNameOfSymbol },
     {"__dyld_NSAddressOfSymbol",                                       (void*)NSAddressOfSymbol },
     {"__dyld_NSModuleForSymbol",                                       (void*)NSModuleForSymbol },
@@ -139,15 +151,12 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_NSAddLibrary",                                                    (void*)NSAddLibrary },
     {"__dyld_NSAddLibraryWithSearching",                       (void*)NSAddLibraryWithSearching },
     {"__dyld_NSAddImage",                                                      (void*)NSAddImage },
-    {"__dyld__NSGetExecutablePath",                                    (void*)_NSGetExecutablePath },
     {"__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_mod_term_funcs",                                          (void*)_dyld_mod_term_funcs },
     {"__dyld_install_link_edit_symbol_handlers",       (void*)dyld::registerZeroLinkHandlers },
     {"__dyld_NSCreateObjectFileImageFromFile",                 (void*)NSCreateObjectFileImageFromFile },
     {"__dyld_NSCreateObjectFileImageFromMemory",               (void*)NSCreateObjectFileImageFromMemory },
-    {"__dyld_NSCreateCoreFileImageFromFile",                   (void*)unimplemented },
     {"__dyld_NSDestroyObjectFileImage",                                        (void*)NSDestroyObjectFileImage },
     {"__dyld_NSLinkModule",                                                            (void*)NSLinkModule },
     {"__dyld_NSHasModInitObjectFileImage",                             (void*)NSHasModInitObjectFileImage },
@@ -158,13 +167,10 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_NSSymbolReferenceCountInObjectFileImage", (void*)NSSymbolReferenceCountInObjectFileImage },
     {"__dyld_NSGetSectionDataInObjectFileImage",               (void*)NSGetSectionDataInObjectFileImage },
     {"__dyld_NSFindSectionAndOffsetInObjectFileImage",  (void*)NSFindSectionAndOffsetInObjectFileImage },
-       {"__dyld_register_thread_helpers",                                      (void*)registerThreadHelpers },
-    {"__dyld_dladdr",                                                                  (void*)dladdr },
-    {"__dyld_dlclose",                                                                 (void*)dlclose },
-    {"__dyld_dlerror",                                                                 (void*)dlerror },
-    {"__dyld_dlopen",                                                                  (void*)dlopen },
-    {"__dyld_dlsym",                                                                   (void*)dlsym },
-       {"__dyld_update_prebinding",                                            (void*)_dyld_update_prebinding },
+#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 },
     {NULL, 0}
 };
@@ -182,7 +188,7 @@ inline const ImageLoader::Symbol* NSSymbolToSymbol(NSSymbol sym)
 }      
 
 // dyld's abstract type NSModule is implemented as ImageLoader*
-inline NSModule ImageLoaderToNSModule(ImageLoader* image)
+inline NSModule ImageLoaderToNSModule(const ImageLoader* image)
 {
        return (NSModule)image;
 }      
@@ -215,7 +221,7 @@ static std::vector<NSObjectFileImage> sObjectFileImages;
 
 static void dyldAPIhalt(const char* apiName, const char* errorMsg)
 {
-       fprintf(stderr, "dyld: %s() error\n", apiName);
+       dyld::log("dyld: %s() error\n", apiName);
        dyld::halt(errorMsg);
 }
 
@@ -244,7 +250,7 @@ static void setLastError(NSLinkEditErrors code, int errnum, const char* file, co
 int _NSGetExecutablePath(char* buf, uint32_t *bufsize)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(...)\n", __func__);
+               dyld::log("%s(...)\n", __func__);
        const char* exePath = dyld::getExecutablePath();
        if(*bufsize < strlen(exePath) + 1){
            *bufsize = strlen(exePath) + 1;
@@ -267,7 +273,7 @@ int _NSGetExecutablePath(char* buf, uint32_t *bufsize)
 static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "__initialize_Cplusplus()\n");
+               dyld::log("__initialize_Cplusplus()\n");
        
        // for now, do nothing...
 }
@@ -276,15 +282,15 @@ static void _dyld_call_module_initializers_for_dylib(const struct mach_header* m
 void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", %p, %p)\n", __func__, symbolName, address, module);
+               dyld::log("%s(\"%s\", %p, %p)\n", __func__, symbolName, address, module);
        ImageLoader* image;
        const ImageLoader::Symbol* sym;
        dyld::clearErrorMessage();
-       if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) { 
+       if ( dyld::flatFindExportedSymbol(symbolName, &sym, (const ImageLoader**)&image) ) {    
                try {
-                       dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers);
+                       image->bindAllLazyPointers(dyld::gLinkContext, true);
                        if ( address != NULL)
-                               *address = (void*)image->getExportedSymbolAddress(sym);
+                               *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                        if ( module != NULL)
                                *module = ImageLoaderToNSModule(image);
                }
@@ -306,12 +312,12 @@ void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModul
 static void client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "_dyld_lookup_and_bind(\"%s\", %p, %p)\n", symbolName, address, module);
-       ImageLoader* image;
+               dyld::log("_dyld_lookup_and_bind(\"%s\", %p, %p)\n", symbolName, address, module);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
                if ( address != NULL)
-                       *address = (void*)image->getExportedSymbolAddress(sym);
+                       *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                if ( module != NULL)
                        *module = ImageLoaderToNSModule(image);
        }
@@ -327,14 +333,14 @@ static void client_dyld_lookup_and_bind(const char* symbolName, void** address,
 void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* library_name_hint, void** address, NSModule* module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", \"%s\", %p, %p)\n", __func__, symbolName, library_name_hint, address, module);
-       ImageLoader* image;
+               dyld::log("%s(\"%s\", \"%s\", %p, %p)\n", __func__, symbolName, library_name_hint, address, module);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        // Look for library whose path contains the hint.  If that fails search everywhere
        if (  dyld::flatFindExportedSymbolWithHint(symbolName, library_name_hint, &sym, &image) 
          ||  dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
                if ( address != NULL)
-                       *address = (void*)image->getExportedSymbolAddress(sym);
+                       *address = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                if ( module != NULL)
                        *module = ImageLoaderToNSModule(image);
        }
@@ -351,8 +357,8 @@ void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* library
 NSSymbol NSLookupAndBindSymbol(const char *symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\")\n", __func__, symbolName);
-       ImageLoader* image;
+               dyld::log("%s(\"%s\")\n", __func__, symbolName);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        if ( dyld::flatFindExportedSymbol(symbolName, &sym, &image) ) {
                return SymbolToNSSymbol(sym);
@@ -364,8 +370,8 @@ NSSymbol NSLookupAndBindSymbol(const char *symbolName)
 NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
-       ImageLoader* image;
+               dyld::log("%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image);
        if ( ! found ) {
@@ -377,21 +383,21 @@ NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libra
                
        // return NULL on failure and log
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", \"%s\") => NULL \n", __func__, symbolName, libraryNameHint);
+               dyld::log("%s(\"%s\", \"%s\") => NULL \n", __func__, symbolName, libraryNameHint);
        return NULL;
 }
 
 uint32_t _dyld_image_count(void)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
+               dyld::log("%s()\n", __func__);
        return dyld::getImageCount();
 }
 
 const struct mach_header* _dyld_get_image_header(uint32_t image_index)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%u)\n", __func__, image_index);
+               dyld::log("%s(%u)\n", __func__, image_index);
        ImageLoader* image = dyld::getIndexedImage(image_index);
        if ( image != NULL )
                return (struct mach_header*)image->machHeader();
@@ -404,28 +410,41 @@ static __attribute__((noinline))
 const struct mach_header* addImage(void* callerAddress, const char* path, bool search, bool dontLoad, bool matchInstallName, bool abortOnError)
 {
        ImageLoader*    image = NULL;
+       std::vector<const char*> rpathsFromCallerImage;
        try {
                dyld::clearErrorMessage();
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
+               // like dlopen, use rpath from caller image and from main executable
+               if ( callerImage != NULL )
+                       callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
+               if ( callerImage != dyld::mainExecutable() ) {
+                       dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               }
                dyld::LoadContext context;
                context.useSearchPaths          = search;
                context.useLdLibraryPath        = false;
+               context.implicitRPath           = false;
                context.matchByInstallName      = matchInstallName;
                context.dontLoad                        = dontLoad;
                context.mustBeBundle            = false;
                context.mustBeDylib                     = true;
+               context.findDLL                         = false;
                context.origin                          = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
-               context.rpath                           = NULL; // support not yet implemented
+               context.rpath                           = &callersRPaths;       // rpaths from caller and main executable
                                
                image = load(path, context);
                if ( image != NULL ) {
                        if ( context.matchByInstallName )
                                image->setMatchInstallPath(true);
-                       dyld::link(image, ImageLoader::kNonLazyOnly, ImageLoader::kRunInitializers);
-                       return image->machHeader();
+                       dyld::link(image, false, callersRPaths);
+                       dyld::runInitializers(image);
+                       // images added with NSAddImage() can never be unloaded
+                       image->setNeverUnload(); 
                }
        }
        catch (const char* msg) {
+               dyld::garbageCollectImages();
                if ( abortOnError) {
                        char pathMsg[strlen(msg)+strlen(path)+4];
                        strcpy(pathMsg, msg);
@@ -435,18 +454,29 @@ const struct mach_header* addImage(void* callerAddress, const char* path, bool s
                }
                // not halting, so set error state for NSLinkEditError to find
                setLastError(NSLinkEditOtherError, 0, path, msg);
+               free((void*)msg);
+               image = NULL;
        }
-       return NULL;
+       // free rpaths (getRPaths() malloc'ed each string)
+       for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
+               const char* str = *it;
+               free((void*)str);
+       }
+       if ( image == NULL )
+               return NULL;
+       else
+               return image->machHeader();
 }
 
+
 const struct mach_header* NSAddImage(const char* path, uint32_t options)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", 0x%08X)\n", __func__, path, options);
+               dyld::log("%s(\"%s\", 0x%08X)\n", __func__, path, options);
        const bool dontLoad = ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 );
        const bool search = ( (options & NSADDIMAGE_OPTION_WITH_SEARCHING) != 0 );
        const bool matchInstallName = ( (options & NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME) != 0 );
-       const bool abortOnError = ( (options & NSADDIMAGE_OPTION_RETURN_ON_ERROR) == 0 );
+       const bool abortOnError = ( (options & NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) == 0 );
        void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
        return addImage(callerAddress, path, search, dontLoad, matchInstallName, abortOnError);
 }
@@ -454,7 +484,7 @@ const struct mach_header* NSAddImage(const char* path, uint32_t options)
 bool NSAddLibrary(const char* path)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\")\n", __func__, path);
+               dyld::log("%s(\"%s\")\n", __func__, path);
        void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
        return (addImage(callerAddress, path, false, false, false, false) != NULL);
 }
@@ -462,7 +492,7 @@ bool NSAddLibrary(const char* path)
 bool NSAddLibraryWithSearching(const char* path)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\")\n", __func__, path);
+               dyld::log("%s(\"%s\")\n", __func__, path);
        void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
        return (addImage(callerAddress, path, true, false, false, false) != NULL);
 }
@@ -476,7 +506,7 @@ bool NSAddLibraryWithSearching(const char* path)
 bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, \"%s\")\n", __func__, (void *)mh, symbolName);
+               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)
@@ -488,17 +518,17 @@ bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symb
 NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", __func__, mh, symbolName, options);
+               dyld::log("%s(%p, \"%s\", 0x%08X)\n", __func__, mh, symbolName, options);
        const ImageLoader::Symbol* symbol = NULL;
        dyld::clearErrorMessage();
        ImageLoader* image = dyld::findImageByMachHeader(mh);
        if ( image != NULL ) {
                try {
                        if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY ) {
-                               dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers);
+                               image->bindAllLazyPointers(dyld::gLinkContext, true);
                        }
                        else if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW ) {
-                               dyld::link(image, ImageLoader::kLazyOnlyNoDependents, ImageLoader::kDontRunInitializers);
+                               image->bindAllLazyPointers(dyld::gLinkContext, false);
                        }
                }
                catch (const char* msg) {
@@ -509,7 +539,7 @@ NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolN
                symbol = image->findExportedSymbol(symbolName, NULL, true, NULL);
        }
        if ( dyld::gLogAPIs && (symbol == NULL) )
-               fprintf(stderr, "%s(%p, \"%s\", 0x%08X) ==> NULL\n", __func__, mh, symbolName, options);
+               dyld::log("%s(%p, \"%s\", 0x%08X) ==> NULL\n", __func__, mh, symbolName, options);
        return SymbolToNSSymbol(symbol);
 }
 
@@ -519,8 +549,8 @@ NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolN
 static bool client_NSIsSymbolNameDefined(const char* symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "NSIsSymbolNameDefined(\"%s\")\n", symbolName);
-       ImageLoader* image;
+               dyld::log("NSIsSymbolNameDefined(\"%s\")\n", symbolName);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        return dyld::flatFindExportedSymbol(symbolName, &sym, &image);
 }
@@ -528,8 +558,8 @@ static bool client_NSIsSymbolNameDefined(const char* symbolName)
 bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
-       ImageLoader* image;
+               dyld::log("%s(\"%s\", \"%s\")\n", __func__, symbolName, libraryNameHint);
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
        bool found = dyld::flatFindExportedSymbolWithHint(symbolName, libraryNameHint, &sym, &image);
        if ( ! found ) {
@@ -537,14 +567,14 @@ bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNa
                 found = dyld::flatFindExportedSymbol(symbolName, &sym, &image);
        }
        if ( !found && dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", \"%s\") => false \n", __func__, symbolName, libraryNameHint);
+               dyld::log("%s(\"%s\", \"%s\") => false \n", __func__, symbolName, libraryNameHint);
        return found;
 }
 
 const char* NSNameOfSymbol(NSSymbol symbol)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol);
+               dyld::log("%s(%p)\n", __func__, (void *)symbol);
        const char* result = NULL;
        ImageLoader* image = dyld::findImageContainingAddress(symbol);
        if ( image != NULL ) 
@@ -555,18 +585,18 @@ const char* NSNameOfSymbol(NSSymbol symbol)
 void* NSAddressOfSymbol(NSSymbol symbol)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol);
+               dyld::log("%s(%p)\n", __func__, (void *)symbol);
        void* result = NULL;
        ImageLoader* image = dyld::findImageContainingAddress(symbol);
        if ( image != NULL ) 
-               result = (void*)image->getExportedSymbolAddress(NSSymbolToSymbol(symbol));
+               result = (void*)image->getExportedSymbolAddress(NSSymbolToSymbol(symbol), dyld::gLinkContext);
        return result;
 }
 
 NSModule NSModuleForSymbol(NSSymbol symbol)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, (void *)symbol);
+               dyld::log("%s(%p)\n", __func__, (void *)symbol);
        NSModule result = NULL;
        ImageLoader* image = dyld::findImageContainingAddress(symbol);
        if ( image != NULL ) 
@@ -578,7 +608,7 @@ NSModule NSModuleForSymbol(NSSymbol symbol)
 intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%u)\n", __func__, image_index);
+               dyld::log("%s(%u)\n", __func__, image_index);
        ImageLoader* image = dyld::getIndexedImage(image_index);
        if ( image != NULL )
                return image->getSlide();
@@ -589,7 +619,7 @@ intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index)
 const char* _dyld_get_image_name(uint32_t image_index)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%u)\n", __func__, image_index);
+               dyld::log("%s(%u)\n", __func__, image_index);
        ImageLoader* image = dyld::getIndexedImage(image_index);
        if ( image != NULL )
                return image->getLogicalPath();
@@ -602,14 +632,14 @@ const char* _dyld_get_image_name(uint32_t image_index)
 bool _dyld_all_twolevel_modules_prebound(void)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
+               dyld::log("%s()\n", __func__);
        return FALSE; // fixme
 }
 
 void _dyld_bind_objc_module(const void *objc_module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objc_module);
+               dyld::log("%s(%p)\n", __func__, objc_module);
        // do nothing, with new dyld everything already bound
 }
 
@@ -617,12 +647,12 @@ void _dyld_bind_objc_module(const void *objc_module)
 bool _dyld_bind_fully_image_containing_address(const void* address)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, address);
+               dyld::log("%s(%p)\n", __func__, address);
        dyld::clearErrorMessage();
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
                try {
-                       dyld::link(image, ImageLoader::kLazyAndNonLazy, ImageLoader::kDontRunInitializers);
+                       image->bindAllLazyPointers(dyld::gLinkContext, true);
                        return true;
                }
                catch (const char* msg) {
@@ -635,7 +665,7 @@ bool _dyld_bind_fully_image_containing_address(const void* address)
 bool _dyld_image_containing_address(const void* address)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, address);
+               dyld::log("%s(%p)\n", __func__, address);
        ImageLoader *imageLoader = dyld::findImageContainingAddress(address);
        return (NULL != imageLoader);
 }
@@ -653,7 +683,7 @@ static NSObjectFileImage createObjectImageFile(ImageLoader* image, const void* a
 NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(\"%s\", ...)\n", __func__, pathName);
+               dyld::log("%s(\"%s\", ...)\n", __func__, pathName);
        try {
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
@@ -661,10 +691,12 @@ NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName
                dyld::LoadContext context;
                context.useSearchPaths          = false;
                context.useLdLibraryPath        = false;
+               context.implicitRPath           = false;
                context.matchByInstallName      = false;
                context.dontLoad                        = false;
                context.mustBeBundle            = true;
                context.mustBeDylib                     = false;
+               context.findDLL                         = false;
                context.origin                          = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
                context.rpath                           = NULL; // support not yet implemented
 
@@ -680,7 +712,9 @@ NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName
                }
        }
        catch (const char* msg) {
-               //fprintf(stderr, "dyld: NSCreateObjectFileImageFromFile() error: %s\n", msg);
+               //dyld::log("dyld: NSCreateObjectFileImageFromFile() error: %s\n", msg);
+               dyld::garbageCollectImages();
+               free((void*)msg);
                return NSObjectFileImageInappropriateFile;
        }
        return NSObjectFileImageFailure;
@@ -690,13 +724,13 @@ NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName
 NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* address, size_t size, NSObjectFileImage *objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, %lu, %p)\n", __func__, address, size, objectFileImage);
+               dyld::log("%s(%p, %lu, %p)\n", __func__, address, size, objectFileImage);
        
        try {
                ImageLoader* image = dyld::loadFromMemory((const uint8_t*)address, size, NULL); 
                if ( ! image->isBundle() ) {
                        // this API can only be used with bundles...
-                       delete image; 
+                       dyld::garbageCollectImages();
                        return NSObjectFileImageInappropriateFile;
                }
                // Note:  We DO NOT link the image!  NSLinkModule will do that
@@ -706,7 +740,9 @@ NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* addres
                }
        }
        catch (const char* msg) {
-               fprintf(stderr, "dyld: NSCreateObjectFileImageFromMemory() error: %s\n", msg);
+               free((void*)msg);
+               dyld::garbageCollectImages();
+               //dyld::log("dyld: NSCreateObjectFileImageFromMemory() error: %s\n", msg);
        }
        return NSObjectFileImageFailure;
 }
@@ -724,14 +760,19 @@ static bool validOFI(NSObjectFileImage objectFileImage)
 bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objectFileImage);
+               dyld::log("%s(%p)\n", __func__, objectFileImage);
        
        if ( validOFI(objectFileImage) ) {
-               // if the image has never been linked or has been unlinked, the image is not in the list of valid images
-               // and we should delete it
-               bool linkedImage = dyld::validImage(objectFileImage->image);
-               if ( ! linkedImage ) 
-                       delete objectFileImage->image;
+               // a failure during NSLinkModule will delete the image
+               if ( objectFileImage->image != NULL ) {
+                       // if the image has never been linked or has been unlinked, the image is not in the list of valid images
+                       // and we should delete it
+                       bool linkedImage = dyld::validImage(objectFileImage->image);
+                       if ( ! linkedImage )  {
+                               delete objectFileImage->image;
+                               objectFileImage->image = NULL;
+                       }
+               }
                
                // remove from list of ofi's
                for (std::vector<NSObjectFileImage>::iterator it=sObjectFileImages.begin(); it != sObjectFileImages.end(); it++) {
@@ -758,21 +799,21 @@ bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)
 bool NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objectFileImage);
+               dyld::log("%s(%p)\n", __func__, objectFileImage);
        return objectFileImage->image->needsInitialization();
 }
 
 uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objectFileImage);
+               dyld::log("%s(%p)\n", __func__, objectFileImage);
        return objectFileImage->image->getExportedSymbolCount();
 }
 
 const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p,%d)\n", __func__, objectFileImage, ordinal);
+               dyld::log("%s(%p,%d)\n", __func__, objectFileImage, ordinal);
        const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedExportedSymbol(ordinal);
        return objectFileImage->image->getExportedSymbolName(sym);      
 }
@@ -780,7 +821,7 @@ const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFile
 uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objectFileImage);
+               dyld::log("%s(%p)\n", __func__, objectFileImage);
        return objectFileImage->image->getImportedSymbolCount();
 }
 
@@ -788,7 +829,7 @@ const char * NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFile
                                                                                                        bool* tentative_definition)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p,%d)\n", __func__, objectFileImage, ordinal);
+               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);
@@ -804,7 +845,7 @@ void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage,
                                                                                const char* segmentName, const char* sectionName, unsigned long* size)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p,%s, %s)\n", __func__, objectFileImage, segmentName, sectionName);
+               dyld::log("%s(%p,%s, %s)\n", __func__, objectFileImage, segmentName, sectionName);
 
        void* start;
        size_t length;
@@ -821,7 +862,7 @@ void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage,
 bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p,%s)\n", __func__, objectFileImage, symbolName);
+               dyld::log("%s(%p,%s)\n", __func__, objectFileImage, symbolName);
        const ImageLoader::Symbol* sym = objectFileImage->image->findExportedSymbol(symbolName, NULL, true, NULL);
        return ( sym != NULL );
 }
@@ -845,9 +886,9 @@ NSFindSectionAndOffsetInObjectFileImage(NSObjectFileImage objectFileImage,
                                                                                unsigned long* sectionOffset)   /* can be NULL */
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, objectFileImage);
+               dyld::log("%s(%p)\n", __func__, objectFileImage);
        
-       return objectFileImage->image->findSection((char*)(objectFileImage->image->getBaseAddress())+imageOffset, segmentName, sectionName, sectionOffset);
+       return objectFileImage->image->findSection(((char*)(objectFileImage->image->machHeader()))+imageOffset, segmentName, sectionName, sectionOffset);
 }
 
 
@@ -855,7 +896,7 @@ NSFindSectionAndOffsetInObjectFileImage(NSObjectFileImage objectFileImage,
 NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", __func__, objectFileImage, moduleName, options); 
+               dyld::log("%s(%p, \"%s\", 0x%08X)\n", __func__, objectFileImage, moduleName, options); 
        
        dyld::clearErrorMessage();
        try {
@@ -864,7 +905,7 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                if ( objectFileImage->image->isLinked() ) {
                        // already linked, so clone a new one and link it
 #if 0
-                       fprintf(stderr, "dyld: warning: %s(0x%08X, \"%s\", 0x%08X) called more than once for 0x%08X\n",
+                       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);
@@ -887,34 +928,40 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                        objectFileImage->image->setHideExports();
        
                // set up linking options
-               ImageLoader::BindingLaziness bindness = ImageLoader::kNonLazyOnly;
-               if ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 )
-                       bindness = ImageLoader::kLazyAndNonLazy;
-               ImageLoader::InitializerRunning runInitializers = ImageLoader::kRunInitializers;
-               if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) != 0 )
-                       runInitializers = ImageLoader::kDontRunInitializersButTellObjc;
+               bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
                
                // load libraries, rebase, bind, to make this image usable
-               dyld::link(objectFileImage->image, bindness, runInitializers);
+               dyld::link(objectFileImage->image, forceLazysBound, ImageLoader::RPathChain(NULL,NULL));
                
+               // 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) {
+               dyld::garbageCollectImages();
                if ( (options & NSLINKMODULE_OPTION_RETURN_ON_ERROR) == 0 )
                        dyldAPIhalt(__func__, msg);
                // not halting, so set error state for NSLinkEditError to find
-               dyld::removeImage(objectFileImage->image);
                setLastError(NSLinkEditOtherError, 0, moduleName, msg);
+               // dyld::link() deleted the image so lose our reference
+               objectFileImage->image = NULL;
+               free((void*)msg);
                return NULL;
        }
 }
 
+
 #if OLD_LIBSYSTEM_SUPPORT
 // This is for compatibility with old libSystems (libdyld.a) which process ObjectFileImages outside dyld
 static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, \"%s\", 0x%08X)\n", "NSLinkModule", object_addr,  moduleName, options); // note name/args translation
+               dyld::log("%s(%p, \"%s\", 0x%08X)\n", "NSLinkModule", object_addr,  moduleName, options); // note name/args translation
        ImageLoader* image = NULL;
        dyld::clearErrorMessage();
        try {
@@ -933,15 +980,14 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
                                image->setHideExports();
                
                        // set up linking options
-                       ImageLoader::BindingLaziness bindness = ImageLoader::kNonLazyOnly;
-                       if ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 )
-                               bindness = ImageLoader::kLazyAndNonLazy;
-                       ImageLoader::InitializerRunning runInitializers = ImageLoader::kRunInitializers;
-                       if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) != 0 )
-                               runInitializers = ImageLoader::kDontRunInitializersButTellObjc;
+                       bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
                        
                        // load libraries, rebase, bind, to make this image usable
-                       dyld::link(image, bindness, runInitializers);
+                       dyld::link(image, forceLazysBound, ImageLoader::RPathChain(NULL,NULL));
+                       
+                       // run initializers unless magic flag says not to
+                       if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) == 0 )
+                               dyld::runInitializers(image);
                }
        }
        catch (const char* msg) {
@@ -955,6 +1001,7 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
                        delete image;
                }
                image = NULL;
+               free((void*)msg);
        }
        return ImageLoaderToNSModule(image);
 }
@@ -963,7 +1010,7 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
 NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, \"%s\")\n", __func__, (void *)module, symbolName);
+               dyld::log("%s(%p, \"%s\")\n", __func__, (void *)module, symbolName);
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return NULL;
@@ -973,7 +1020,7 @@ NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
 const char* NSNameOfModule(NSModule module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, module);
+               dyld::log("%s(%p)\n", __func__, module);
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return NULL;
@@ -983,7 +1030,7 @@ const char* NSNameOfModule(NSModule module)
 const char* NSLibraryNameForModule(NSModule module)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, module);
+               dyld::log("%s(%p)\n", __func__, module);
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return NULL;
@@ -993,7 +1040,7 @@ const char* NSLibraryNameForModule(NSModule module)
 bool NSUnLinkModule(NSModule module, uint32_t options)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, 0x%08X)\n", __func__, module, options); 
+               dyld::log("%s(%p, 0x%08X)\n", __func__, module, options); 
        if ( module == NULL )
                return false;
        ImageLoader* image = NSModuleToImageLoader(module);
@@ -1025,7 +1072,7 @@ bool NSUnLinkModule(NSModule module, uint32_t options)
 static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "NSLinkEditErrorHandlers()\n");
+               dyld::log("NSLinkEditErrorHandlers()\n");
 
        dyld::registerUndefinedHandler((dyld::UndefinedHandler)undefined);
        // no support for multiple or linkedit handlers
@@ -1034,7 +1081,7 @@ static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEd
 const struct mach_header * _dyld_get_image_header_containing_address(const void* address)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, address);
+               dyld::log("%s(%p)\n", __func__, address);
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) 
                return image->machHeader();
@@ -1045,31 +1092,28 @@ const struct mach_header * _dyld_get_image_header_containing_address(const void*
 void _dyld_register_func_for_add_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, (void *)func);
+               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 )
-               fprintf(stderr, "%s(%p)\n", __func__, (void *)func);
+               dyld::log("%s(%p)\n", __func__, (void *)func);
        dyld::registerRemoveCallback(func);
 }
 
-// called by atexit() function installed by crt
-static void _dyld_mod_term_funcs()
-{
-       if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-       dyld::runTerminators();
-}
 
 // called by crt before main
 static void _dyld_make_delayed_module_initializer_calls()
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-       dyld::initializeMainExecutable();
+               dyld::log("%s()\n", __func__);
+               
+#if SUPPORT_OLD_CRT_INITIALIZATION
+       if ( dyld::gRunInitializersOldWay )
+               dyld::initializeMainExecutable();
+#endif
 }
 
 
@@ -1085,30 +1129,17 @@ void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileNam
 static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *, const char *, void *), ImageLoader::BindingOptions bindingOptions)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
+               dyld::log("%s()\n", __func__);
        dyld::gLinkContext.bindingHandler = bindingHandler;
        dyld::gLinkContext.bindingOptions = bindingOptions;
 }
 
-// Call by fork() in libSystem before the kernel trap is done
-static void _dyld_fork_prepare()
-{
-       if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-}
-
-// Call by fork() in libSystem after the kernel trap is done on the parent side
-static void _dyld_fork_parent()
-{
-       if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-}
 
 // Call by fork() in libSystem after the kernel trap is done on the child side
 static void _dyld_fork_child()
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
+               dyld::log("%s()\n", __func__);
        // The implementation of fork() in libSystem knows to reset the variable mach_task_self_
        // in libSystem for the child of a fork.  But dyld is built with a static copy
        // of libc.a and has its own copy of mach_task_self_ which we reset here.
@@ -1120,13 +1151,6 @@ static void _dyld_fork_child()
        mach_task_self_ = task_self_trap();
 }
 
-// Call by fork() in libSystem after the kernel trap is done on the child side after
-// other libSystem child side fixups are done
-static void _dyld_fork_child_final()
-{
-       if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-}
 
 
 typedef void (*MonitorProc)(char *lowpc, char *highpc);
@@ -1155,7 +1179,7 @@ void _dyld_moninit(MonitorProc proc)
 bool _dyld_launched_prebound()
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
+               dyld::log("%s()\n", __func__);
                
        // Â¥Â¥Â¥ÃŠif we deprecate prebinding, we may want to consider always returning true or false here
        return dyld::mainExecutablePrebound();
@@ -1188,7 +1212,7 @@ bool lookupDyldFunction(const char* name, uintptr_t* address)
        for (const dyld_func* p = dyld_funcs; p->name != NULL; ++p) {
            if ( strcmp(p->name, name) == 0 ) {
                        if( p->implementation == unimplemented )
-                               fprintf(stderr, "unimplemented dyld function: %s\n", p->name);
+                               dyld::log("unimplemented dyld function: %s\n", p->name);
                        *address = (uintptr_t)p->implementation;
                        return true;
            }
@@ -1197,80 +1221,179 @@ bool lookupDyldFunction(const char* name, uintptr_t* address)
        return false;
 }
 
-
-static void registerThreadHelpers(const dyld::ThreadingHelpers* helpers)
+static bool readOnlyBootVolume()
 {
-       // We need to make sure libSystem's lazy pointer's are bound
-       // before installing thred helpers.
-       // The reason for this is that if accessing the lock requires
-       // a lazy pointer to be bound (and it does when multi-module
-       // libSystem) is not prebound, the lazy handler will be
-       // invoked which tries to acquire the lock again...an infinite 
-       // loop.
-       ImageLoader* image = dyld::findImageContainingAddress(helpers);
-       dyld::link(image, ImageLoader::kLazyOnly, ImageLoader::kDontRunInitializers);
+       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;
+}
 
-       dyld::gThreadHelpers = helpers;
+
+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::gSharedCacheNeedsUpdating )
+                                       (*helpers->dyld_shared_cache_out_of_date)();
+                       }
+               }
+       }
+#endif
 }
 
 
 static void dlerrorClear()
 {
-       if ( dyld::gThreadHelpers != NULL ) {
-               char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(1);
+       if ( dyld::gLibSystemHelpers != NULL ) {
+               // first char of buffer is flag whether string (starting at second char) is valid
+               char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
                buffer[0] = '\0';
+               buffer[1] = '\0';
        }
 }
 
 static void dlerrorSet(const char* msg)
 {
-       if ( dyld::gThreadHelpers != NULL ) {
-               char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(strlen(msg)+1);
-               strcpy(buffer, msg);
+       if ( dyld::gLibSystemHelpers != NULL ) {
+               // first char of buffer is flag whether string (starting at second char) is valid
+               char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(strlen(msg)+2);
+               buffer[0] = '\1';
+               strcpy(&buffer[1], msg);
        }
 }
 
 
+bool dlopen_preflight(const char* path)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%s)\n", __func__, path);
+
+       dlerrorClear();
+       
+       bool result = false;
+       std::vector<const char*> rpathsFromCallerImage;
+       try {
+               void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
+               ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
+               // for dlopen, use rpath from caller image and from main executable
+               if ( callerImage != NULL )
+                       callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
+               if ( callerImage != dyld::mainExecutable() ) {
+                       dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               }
+
+               ImageLoader*    image = NULL;
+               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.matchByInstallName = true;
+               context.dontLoad                = false;
+               context.mustBeBundle    = false;
+               context.mustBeDylib             = false;
+               context.findDLL                 = false;
+               context.origin                  = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
+               context.rpath                   = &callersRPaths;       // rpaths from caller and main executable
+               
+               image = load(path, context);
+               if ( image != NULL ) {
+                       dyld::preflight(image, callersRPaths);  // image object deleted by dyld::preflight()
+                       result = true;
+               }
+       }
+       catch (const char* msg) {
+               const char* str = dyld::mkstringf("dlopen_preflight(%s): %s", path, msg);
+               dlerrorSet(str);
+               free((void*)str);
+       }
+       // free rpaths (getRPaths() malloc'ed each string)
+       for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
+               const char* str = *it;
+               free((void*)str);
+       }
+       return result;
+}
+
 
 void* dlopen(const char* path, int mode)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%s, 0x%08X)\n", __func__, path, mode);
+               dyld::log("%s(%s, 0x%08X)\n", __func__, ((path==NULL) ? "NULL" : path), mode);
 
        dlerrorClear();
        
        // passing NULL for path means return magic object
        if ( path == NULL ) {
-               return RTLD_DEFAULT;
+               // RTLD_FIRST means any dlsym() calls on the handle should only search that handle and not subsequent images
+               if ( (mode & RTLD_FIRST) != 0 )
+                       return RTLD_MAIN_ONLY;
+               else
+                       return RTLD_DEFAULT;
        }
        
+       // acquire global dyld lock (dlopen is special - libSystem glue does not do locking)
+       bool lockHeld = false;
+       if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 4) ) {
+               dyld::gLibSystemHelpers->acquireGlobalDyldLock();
+               lockHeld = true;
+       }
+               
+       void* result = NULL;
+       ImageLoader* image = NULL;
+       std::vector<const char*> rpathsFromCallerImage;
        try {
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
-
-               ImageLoader*    image = NULL;
+               // for dlopen, use rpath from caller image and from main executable
+               if ( callerImage != NULL )
+                       callerImage->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               ImageLoader::RPathChain callersRPaths(NULL, &rpathsFromCallerImage);
+               if ( callerImage != dyld::mainExecutable() ) {
+                       dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
+               }
                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.matchByInstallName = true;
-               context.dontLoad = ( (mode & RTLD_NOLOAD) != 0 );
+               context.dontLoad                = ( (mode & RTLD_NOLOAD) != 0 );
                context.mustBeBundle    = false;
                context.mustBeDylib             = false;
+               context.findDLL                 = ( (mode & RTLD_DLL) != 0 );
                context.origin                  = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
-               context.rpath                   = NULL; // support not yet implemented
+               context.rpath                   = &callersRPaths;                               // rpaths from caller and main executable
                
                image = load(path, context);
                if ( image != NULL ) {
-                       image->incrementReferenceCount();
-                       if ( ! image->isLinked() ) {
-                               ImageLoader::BindingLaziness bindiness = ImageLoader::kNonLazyOnly;
-                               if ( (mode & RTLD_NOW) != 0 )
-                                       bindiness = ImageLoader::kLazyAndNonLazy;
-                               dyld::link(image, bindiness, ImageLoader::kRunInitializers);
-                               // only hide exports if image is not already in use
-                               if ( (mode & RTLD_LOCAL) != 0 )
-                                       image->setHideExports(true);
+                       // bump reference count.  Do this before link() so that if an initializer calls dlopen and fails
+                       // this image is not garbage collected
+                       image->incrementDlopenReferenceCount();
+                       // link in all dependents
+                       if ( (mode & RTLD_NOLOAD) == 0 ) {
+                               bool alreadyLinked = image->isLinked();
+                               bool forceLazysBound = ( (mode & RTLD_NOW) != 0 );
+                               dyld::link(image, forceLazysBound, callersRPaths);
+                               if ( ! alreadyLinked ) {
+                                       // only hide exports if image is not already in use
+                                       if ( (mode & RTLD_LOCAL) != 0 )
+                                               image->setHideExports(true);
+                               }
                        }
+                       
                        // RTLD_NODELETE means don't unmap image even after dlclosed. This is what dlcompat did on Mac OS X 10.3
                        // On other *nix OS's, it means dlclose() should do nothing, but the handle should be invalidated. 
                        // The subtle differences are: 
@@ -1278,34 +1401,77 @@ void* dlopen(const char* path, int mode)
                        //  2) If someone does a supsequent dlopen() on the same image, whether the same address should be used. 
                        if ( (mode & RTLD_NODELETE) != 0 )
                                image->setLeaveMapped();
-                       return image;
+                       
+                       // release global dyld lock early, this enables initializers to do threaded operations
+                       if ( lockHeld ) {
+                               dyld::gLibSystemHelpers->releaseGlobalDyldLock();
+                               lockHeld = false;
+                       }
+                       
+                       // RTLD_NOLOAD means dlopen should fail unless path is already loaded. 
+                       // don't run initializers when RTLD_NOLOAD is set.  This only matters if dlopen() is
+                       // called from within an initializer because it can cause initializers to run
+                       // out of order. Most uses of RTLD_NOLOAD are "probes".  If they want initialzers
+                       // to run, then don't use RTLD_NOLOAD.
+                       if ( (mode & RTLD_NOLOAD) == 0 ) {
+                               // run initializers
+                               dyld::runInitializers(image);
+                       }
+                       
+                       // RTLD_FIRST means any dlsym() calls on the handle should only search that handle and not subsequent images
+                       // this is tracked by setting the low bit of the handle, which is usually zero by malloc alignment
+                       if ( (mode & RTLD_FIRST) != 0 )
+                               result = (void*)(((uintptr_t)image)|1);
+                       else
+                               result = image;
                }
        }
        catch (const char* msg) {
-               const char* format = "dlopen(%s, %d): %s";
-               char temp[strlen(format)+strlen(path)+strlen(msg)+10];
-               sprintf(temp, format, path, mode, msg);
-               dlerrorSet(temp);
+               if ( image != NULL ) {
+                       // load() succeeded but, link() failed
+                       // back down reference count and do GC
+                       image->decrementDlopenReferenceCount();
+                       dyld::garbageCollectImages();
+               }
+               const char* str = dyld::mkstringf("dlopen(%s, %d): %s", path, mode, msg);
+               dlerrorSet(str);
+               free((void*)str);
+               result = NULL;
        }
-       return NULL;
+       // free rpaths (getRPaths() malloc'ed each string)
+       for(std::vector<const char*>::iterator it=rpathsFromCallerImage.begin(); it != rpathsFromCallerImage.end(); ++it) {
+               const char* str = *it;
+               free((void*)str);
+       }
+       
+       if ( lockHeld ) 
+               dyld::gLibSystemHelpers->releaseGlobalDyldLock();
+       return result;
 }
 
+
+
 int dlclose(void* handle)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p)\n", __func__, handle);
+               dyld::log("%s(%p)\n", __func__, handle);
 
-       ImageLoader* image = (ImageLoader*)handle;
+       // silently accept magic handles for main executable
+       if ( handle == RTLD_MAIN_ONLY )
+               return 0;
+       if ( handle == RTLD_DEFAULT )
+               return 0;
+       
+       ImageLoader* image = (ImageLoader*)(((uintptr_t)handle) & (-4));        // clear mode bits
        if ( dyld::validImage(image) ) {
-               if ( image->decrementReferenceCount() ) {
-                       // for now, only bundles can be unloaded
-                       // to unload dylibs we would need to track all direct and indirect uses
-                       if ( image->isBundle() ) {
-                               dyld::removeImage(image);
-                               delete image;
-                       }
-               }
                dlerrorClear();
+               // decrement use count
+               if ( image->decrementDlopenReferenceCount() ) {
+                       dlerrorSet("dlclose() called too many times");
+                       return -1;
+               }
+               // remove image if reference count went to zero
+               dyld::garbageCollectImages();
                return 0;
        }
        else {
@@ -1319,7 +1485,7 @@ int dlclose(void* handle)
 int dladdr(const void* address, Dl_info* info)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, %p)\n", __func__, address, info);
+               dyld::log("%s(%p, %p)\n", __func__, address, info);
 
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
@@ -1331,14 +1497,16 @@ int dladdr(const void* address, Dl_info* info)
                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);
+                       const void* symAddr = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                        if ( (symAddr <= address) && (bestAddr < symAddr) ) {
                                bestSym = sym;
                                bestAddr = symAddr;
                        }
                }
                if ( bestSym != NULL ) {
-                       info->dli_sname = image->getExportedSymbolName(bestSym) + 1; // strip off leading underscore
+                       info->dli_sname = image->getExportedSymbolName(bestSym);
+                       if ( info->dli_sname[0] == '_' )
+                               info->dli_sname = info->dli_sname +1; // strip off leading underscore
                        info->dli_saddr = (void*)bestAddr;
                }
                else {
@@ -1354,13 +1522,15 @@ int dladdr(const void* address, Dl_info* info)
 char* dlerror()
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
-
-       if ( dyld::gThreadHelpers != NULL ) {
-               char* buffer = (*dyld::gThreadHelpers->getThreadBufferFor_dlerror)(1);
-               // if no error set, return NULL
-               if ( buffer[0] != '\0' )
-                       return buffer;
+               dyld::log("%s()\n", __func__);
+
+       if ( dyld::gLibSystemHelpers != NULL ) {
+               // first char of buffer is flag whether string (starting at second char) is valid
+               char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
+               if ( buffer[0] != '\0' ) {      // if valid buffer
+                       buffer[0] = '\0';               // mark invalid, so next call to dlerror returns NULL
+                       return &buffer[1];              // return message
+               }
        }
        return NULL;
 }
@@ -1368,11 +1538,11 @@ char* dlerror()
 void* dlsym(void* handle, const char* symbolName)
 {
        if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s(%p, %s)\n", __func__, handle, symbolName);
+               dyld::log("%s(%p, %s)\n", __func__, handle, symbolName);
 
        dlerrorClear();
 
-       ImageLoader* image;
+       const ImageLoader* image;
        const ImageLoader::Symbol* sym;
 
        // dlsym() assumes symbolName passed in is same as in C source code
@@ -1384,12 +1554,24 @@ void* dlsym(void* handle, const char* symbolName)
        // magic "search all" handle
        if ( handle == RTLD_DEFAULT ) {
                if ( dyld::flatFindExportedSymbol(underscoredName, &sym, &image) ) {
-                       return (void*)image->getExportedSymbolAddress(sym);
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
-               const char* format = "dlsym(RTLD_DEFAULT, %s): symbol not found";
-               char temp[strlen(format)+strlen(symbolName)+2];
-               sprintf(temp, format, symbolName);
-               dlerrorSet(temp);
+               const char* str = dyld::mkstringf("dlsym(RTLD_DEFAULT, %s): symbol not found", symbolName);
+               dlerrorSet(str);
+               free((void*)str);
+               return NULL;
+       }
+       
+       // 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
+               if ( sym != NULL ) {
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
+               }
+               const char* str = dyld::mkstringf("dlsym(RTLD_MAIN_ONLY, %s): symbol not found", symbolName);
+               dlerrorSet(str);
+               free((void*)str);
                return NULL;
        }
        
@@ -1397,43 +1579,42 @@ void* dlsym(void* handle, const char* symbolName)
        if ( handle == RTLD_NEXT ) {
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
-               sym = callerImage->findExportedSymbolInDependentImages(underscoredName, &image); // don't search image, but do search what it links against
+               sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
                if ( sym != NULL ) {
-                       return (void*)image->getExportedSymbolAddress(sym);
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
-               const char* format = "dlsym(RTLD_NEXT, %s): symbol not found";
-               char temp[strlen(format)+strlen(symbolName)+2];
-               sprintf(temp, format, symbolName);
-               dlerrorSet(temp);
+               const char* str = dyld::mkstringf("dlsym(RTLD_NEXT, %s): symbol not found", symbolName);
+               dlerrorSet(str);
+               free((void*)str);
                return NULL;
        }
-#ifdef RTLD_SELF
        // magic "search me, then what I would see" handle
        if ( handle == RTLD_SELF ) {
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
-               sym = callerImage->findExportedSymbolInImageOrDependentImages(underscoredName, &image); // search image and what it links against
+               sym = callerImage->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                if ( sym != NULL ) {
-                       return (void*)image->getExportedSymbolAddress(sym);
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
-               const char* format = "dlsym(RTLD_SELF, %s): symbol not found";
-               char temp[strlen(format)+strlen(symbolName)+2];
-               sprintf(temp, format, symbolName);
-               dlerrorSet(temp);
+               const char* str = dyld::mkstringf("dlsym(RTLD_SELF, %s): symbol not found", symbolName);
+               dlerrorSet(str);
+               free((void*)str);
                return NULL;
        }
-#endif
        // real handle
-       image = (ImageLoader*)handle;
+       image = (ImageLoader*)(((uintptr_t)handle) & (-4));     // clear mode bits
        if ( dyld::validImage(image) ) {
-               sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, &image); // search image and what it links against
+               if ( (((uintptr_t)handle) & 1) != 0 )
+                       sym = image->findExportedSymbol(underscoredName, NULL, true, &image); // search RTLD_FIRST way
+               else
+                       sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
+               
                if ( sym != NULL ) {
-                       return (void*)image->getExportedSymbolAddress(sym);
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
-               const char* format = "dlsym(%p, %s): symbol not found";
-               char temp[strlen(format)+strlen(symbolName)+20];
-               sprintf(temp, format, handle, symbolName);
-               dlerrorSet(temp);
+               const char* str = dyld::mkstringf("dlsym(%p, %s): symbol not found", handle, symbolName);
+               dlerrorSet(str);
+               free((void*)str);
        }
        else {
                dlerrorSet("invalid handle passed to dlsym()");
@@ -1442,196 +1623,69 @@ void* dlsym(void* handle, const char* symbolName)
 }
 
 
-static void commitRepreboundFiles(std::vector<ImageLoader*> files, bool unmapOld)
+
+void* dlord(void* handle, uint32_t ordinal)
 {
-       // tell file system to flush all dirty buffers to disk
-       // after this sync, the _redoprebinding files will be on disk
-       sync();
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p, %u)\n", __func__, handle, ordinal);
 
-       // now commit (swap file) for each re-prebound image
-       // this only updates directories, since the files have already been flushed by previous sync()
-       for (std::vector<ImageLoader*>::iterator it=files.begin(); it != files.end(); it++) {
-               (*it)->reprebindCommit(dyld::gLinkContext, true, unmapOld);
-       }
+       dlerrorClear();
 
-       // tell file system to flush all dirty buffers to disk
-       // this should flush out all directory changes caused by the file swapping
-       sync();
+       
+       // 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;
 }
 
 
-#define UPDATE_PREBINDING_DRY_RUN  0x00000001
-#define UPDATE_PREBINDING_PROGRESS 0x00000002
 
-//
-// SPI called only by update_prebinding tool to redo prebinding in all prebound files specified
-// There must be no dylibs loaded when this fnction is called.
-//
-__attribute__((noreturn))
-static void _dyld_update_prebinding(int pathCount, const char* paths[], uint32_t flags)
-{
-       if ( dyld::gLogAPIs )
-               fprintf(stderr, "%s()\n", __func__);
 
-       // list of requested dylibs actually loaded
-       std::vector<ImageLoader*> preboundImages;
-       
-       try {
-               // verify no dylibs loaded
-               if ( dyld::getImageCount() != 1 )
-                       throw "_dyld_update_prebinding cannot be called with dylib already loaded";
-                       
-               // note that we are prebinding
-               dyld::gLinkContext.prebinding = true;
 
-               const uint32_t max_allowed_link_errors = 100;
-               uint32_t link_error_count = 0;
-               
-               // load and link each dylib
-               for (int i=0; i < pathCount; ++i) {
-                       dyld::LoadContext context;
-                       context.useSearchPaths          = false;
-                       context.matchByInstallName      = true;
-                       context.dontLoad                        = false;
-                       context.mustBeBundle            = false;
-                       context.mustBeDylib                     = true;
-                       context.origin                          = NULL;         // @loader_path not allowed in prebinding list
-                       context.rpath                           = NULL;         // support not yet implemented
-                       
-                       ImageLoader* image = NULL;
-                       try {
-                               image = dyld::load(paths[i], context);
-                               // bind lazy and non-lazy symbols, but don't run initializers
-                               // this may bring in other dylibs later in the list or missing from list, but that is ok
-                               dyld::link(image, ImageLoader::kLazyAndNonLazy, ImageLoader::kDontRunInitializers);
-                               // recored images we successfully loaded
-                               preboundImages.push_back(image);
-                       }
-                       catch (const char* msg) {
-                               if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) ) {
-                                       const char *stage;
-                                       if ( image == NULL ) // load exception
-                                               stage = "load";
-                                       else // link exception
-                                               stage = "link";
-                                       fprintf(stderr, "update_prebinding: warning: could not %s %s: %s\n", stage, paths[i], msg);
-                               }
-                               if ( (image != NULL) && image->isPrebindable() ) // don't count top level dylib being unprebound as an error
-                                       link_error_count++;
-                               if ( link_error_count > max_allowed_link_errors ) {
-                                       fprintf(stderr, "update_prebinding: too many errors (%d) \n", link_error_count);
-                                       throw "terminating";
-                               }
-                       }
-               }
-               
-               // find missing images
-               uint32_t loadedImageCount =     dyld::getImageCount();
-               if ( loadedImageCount > (preboundImages.size()+1) ) {
-                       if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) )
-                               fprintf(stderr, "update_prebinding: warning: the following dylibs were loaded but will not have their prebinding updated because they are not in the list of paths to reprebind\n");
-                       for (uint32_t i=1; i < loadedImageCount; ++i) {
-                               ImageLoader* target = dyld::getIndexedImage(i);
-                               bool found = false;
-                               for (std::vector<ImageLoader*>::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) {
-                                       if ( *it == target ) {
-                                               found = true;
-                                               break;
-                                       }
-                               }
-                               if ( !found ) 
-                                       if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) )
-                                               fprintf(stderr, "  %s\n", target->getPath());
-                       }
-               }
 
-               // warn about unprebound files in the list
-               bool unpreboundWarned = false;
-               for (std::vector<ImageLoader*>::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) {
-                       if ( ! (*it)->isPrebindable() && (*it != dyld::mainExecutable()) ) {
-                               if ( ! unpreboundWarned ) {
-                                       if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) )
-                                               fprintf(stderr, "update_prebinding: warning: the following dylibs were specified but were not built prebound\n");
-                                       unpreboundWarned = true;
-                               }
-                               if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) )
-                                       fprintf(stderr, "  %s\n", (*it)->getPath());
-                       }
-               }
-               
-               if(UPDATE_PREBINDING_DRY_RUN & flags) {
-                       fprintf(stderr, "update_prebinding: dry-run: no changes were made to the filesystem.\n");
-               }
-               else {
-                       uint32_t imageCount = preboundImages.size();
-                       uint32_t imageNumber = 1;
-
-                       // on Intel system, update_prebinding is run twice: i386, then emulated ppc
-                       // calculate fudge factors so that progress output represents both runs
-                       int denomFactor = 1;
-                       int numerAddend = 0;
-                       if (UPDATE_PREBINDING_PROGRESS & flags) {
-               #if __i386__
-                               // i386 half runs first, just double denominator
-                               denomFactor = 2;
-               #endif  
-               #if __ppc__
-                               // if emulated ppc, double denominator and shift numerator
-                               int mib[] = { CTL_KERN, KERN_CLASSIC, getpid() };
-                               int is_emulated = 0;
-                               size_t len = sizeof(int);
-                               int ret = sysctl(mib, 3, &is_emulated, &len, NULL, 0);
-                               if ((ret != -1) && is_emulated) {
-                                       denomFactor = 2;
-                                       numerAddend = imageCount;
-                               }
-               #endif
-                       }
 
-                       // tell each image to write itself out re-prebound
-                       struct timeval currentTime = { 0 , 0 };
-                       gettimeofday(&currentTime, NULL);
-                       time_t timestamp = currentTime.tv_sec;
-                       std::vector<ImageLoader*> updatedImages;
-                       for (std::vector<ImageLoader*>::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) {
-                               uint64_t freespace = (*it)->reprebind(dyld::gLinkContext, timestamp);
-                               updatedImages.push_back(*it);
-                               if(UPDATE_PREBINDING_PROGRESS & flags) {
-                                       fprintf(stdout, "update_prebinding: progress: %3u/%u\n", imageNumber+numerAddend, imageCount*denomFactor);
-                                       fflush(stdout);
-                                       imageNumber++;
-                               }
-                               // see if we are running low on disk space (less than 32MB is "low")
-                               const uint64_t kMinFreeSpace = 32*1024*1024;  
-                               if ( freespace < kMinFreeSpace ) {
-                                       if ( dyld::gLinkContext.verbosePrebinding || (UPDATE_PREBINDING_DRY_RUN & flags) )
-                                               fprintf(stderr, "update_prebinding: disk space down to %lluMB, committing %lu prebound files\n", freespace/(1024*1024), updatedImages.size());
-                                       // commit files processed so far, to free up more disk space
-                                       commitRepreboundFiles(updatedImages, true);
-                                       // empty list of temp files
-                                       updatedImages.clear();
-                               }
-                       }
-               
-                       // commit them, don't need to unmap old, cause we are done
-                       commitRepreboundFiles(updatedImages, false);
-               }
-       }
-       catch (const char* msg) {
-               // delete temp files
-               try {
-                       for (std::vector<ImageLoader*>::iterator it=preboundImages.begin(); it != preboundImages.end(); it++) {
-                               (*it)->reprebindCommit(dyld::gLinkContext, false, false);
-                       }
-               }
-               catch (const char* commitMsg) {
-                       fprintf(stderr, "update_prebinding: error: %s\n", commitMsg);
-               }
-               fprintf(stderr, "update_prebinding: error: %s\n", msg);
-               exit(1);
-       }
-       exit(0);
-}
 
 
 
@@ -1642,6 +1696,19 @@ static const struct dyld_all_image_infos* _dyld_get_all_image_infos()
 
 
 
+void dyld_register_image_state_change_handler(dyld_image_states state, bool batch, 
+                                                                                       dyld_image_state_change_handler handler)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%d, %d, %p)\n", __func__, state, batch, handler);
+       if ( batch )
+               dyld::registerImageStateBatchChangeHandler(state, handler);
+       else
+               dyld::registerImageStateSingleChangeHandler(state, handler);
+}
+
+
+
 
 
 
index 67f4eb77f3d80d2b2714da3da19e1b138eeeddb0..fbc172f3dda1cd57f22444bb593c9c15095e10c0 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -31,6 +31,9 @@
 
 #include "dyldLock.h"
 
+extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
+
+
 /*
  * names_match() takes an install_name from an LC_LOAD_DYLIB command and a
  * libraryName (which is -lx or -framework Foo argument passed to the static
@@ -87,7 +90,7 @@ const char* libraryName)
 void NSInstallLinkEditErrorHandlers(
 const NSLinkEditErrorHandlers* handlers)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(
        void     (*undefined)(const char* symbol_name),
        NSModule (*multiple)(NSSymbol s, NSModule old, NSModule newhandler),
@@ -103,7 +106,7 @@ const char*
 NSNameOfModule(
 NSModule module)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const char*  (*p)(NSModule module) = NULL;
 
        if(p == NULL)
@@ -115,7 +118,7 @@ const char*
 NSLibraryNameForModule(
 NSModule module)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const char*  (*p)(NSModule module) = NULL;
 
        if(p == NULL)
@@ -127,7 +130,7 @@ bool
 NSIsSymbolNameDefined(
 const char* symbolName)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const char* symbolName) = NULL;
 
        if(p == NULL)
@@ -140,7 +143,7 @@ NSIsSymbolNameDefinedWithHint(
 const char* symbolName,
 const char* libraryNameHint)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const char* symbolName,
                          const char* libraryNameHint) = NULL;
 
@@ -154,7 +157,7 @@ NSIsSymbolNameDefinedInImage(
 const struct mach_header *image,
 const char* symbolName)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const struct mach_header *image,
                          const char* symbolName) = NULL;
 
@@ -167,7 +170,7 @@ NSSymbol
 NSLookupAndBindSymbol(
 const char* symbolName)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSSymbol (*p)(const char* symbolName) = NULL;
 
        if(p == NULL)
@@ -180,7 +183,7 @@ NSLookupAndBindSymbolWithHint(
 const char* symbolName,
 const char* libraryNameHint)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSSymbol (*p)(const char* symbolName,
                         const char* libraryNameHint) = NULL;
 
@@ -194,7 +197,7 @@ NSLookupSymbolInModule(
 NSModule module,
 const char* symbolName)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSSymbol (*p)(NSModule module, const char* symbolName) = NULL;
 
        if(p == NULL)
@@ -208,7 +211,7 @@ const struct mach_header *image,
 const char* symbolName,
 uint32_t options)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
    static NSSymbol (*p)(const struct mach_header *image,
                         const char* symbolName,
                         uint32_t options) = NULL;
@@ -222,7 +225,7 @@ const char*
 NSNameOfSymbol(
 NSSymbol symbol)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static char * (*p)(NSSymbol symbol) = NULL;
 
        if(p == NULL)
@@ -234,7 +237,7 @@ void *
 NSAddressOfSymbol(
 NSSymbol symbol)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void * (*p)(NSSymbol symbol) = NULL;
 
        if(p == NULL)
@@ -246,7 +249,7 @@ NSModule
 NSModuleForSymbol(
 NSSymbol symbol)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSModule (*p)(NSSymbol symbol) = NULL;
 
        if(p == NULL)
@@ -258,7 +261,7 @@ bool
 NSAddLibrary(
 const char* pathName)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const char* pathName) = NULL;
 
        if(p == NULL)
@@ -270,7 +273,7 @@ bool
 NSAddLibraryWithSearching(
 const char* pathName)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const char* pathName) = NULL;
 
        if(p == NULL)
@@ -283,7 +286,7 @@ NSAddImage(
 const char* image_name,
 uint32_t options)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const struct mach_header * (*p)(const char* image_name,
                                           uint32_t options) = NULL;
 
@@ -311,30 +314,30 @@ const char* libraryName)
     struct load_command *load_commands, *lc;
     struct dylib_command *dl;
     char *install_name;
-#ifndef __OPENSTEP__
+#if __LP64__
+    static struct mach_header_64 *mh = NULL;
+#else
     static struct mach_header *mh = NULL;
+#endif
        if(mh == NULL)
            mh = _NSGetMachExecuteHeader();
-#else /* defined(__OPENSTEP__) */
-#ifdef __DYNAMIC__
-    static struct mach_header *mh = NULL;
-       if(mh == NULL)
-           _dyld_lookup_and_bind("__mh_execute_header", &mh, NULL);
+       load_commands = (struct load_command *)
+#if __LP64__
+                           ((char *)mh + sizeof(struct mach_header_64));
 #else
-    struct mach_header *mh;
-       mh = (struct mach_header *)&_mh_execute_header;
+                           ((char *)mh + sizeof(struct mach_header));
 #endif
-#endif /* __OPENSTEP__ */
-       load_commands = (struct load_command *)
-                       ((char *)mh + sizeof(struct mach_header));
        lc = load_commands;
        for(i = 0; i < mh->ncmds; i++){
-           if(lc->cmd == LC_LOAD_DYLIB){
-               dl = (struct dylib_command *)lc;
-               install_name = (char *)dl + dl->dylib.name.offset;
-               if(names_match(install_name, libraryName) == TRUE)
-                   return(dl->dylib.current_version);
-           }
+               switch ( lc->cmd ) { 
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               dl = (struct dylib_command *)lc;
+                               install_name = (char *)dl + dl->dylib.name.offset;
+                               if(names_match(install_name, libraryName) == TRUE)
+                                       return(dl->dylib.current_version);
+                               break;
+               }
            lc = (struct load_command *)((char *)lc + lc->cmdsize);
        }
        return(-1);
@@ -363,7 +366,11 @@ const char* libraryName)
            if(mh->filetype != MH_DYLIB)
                continue;
            load_commands = (struct load_command *)
+#if __LP64__
+                           ((char *)mh + sizeof(struct mach_header_64));
+#else
                            ((char *)mh + sizeof(struct mach_header));
+#endif
            lc = load_commands;
            for(j = 0; j < mh->ncmds; j++){
                if(lc->cmd == LC_ID_DYLIB){
@@ -390,7 +397,7 @@ NSCreateObjectFileImageFromFile(
 const char* pathName,
 NSObjectFileImage *objectFileImage)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL;
 
        if(p == NULL)
@@ -412,7 +419,7 @@ const void* address,
 size_t size, 
 NSObjectFileImage *objectFileImage)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSObjectFileImageReturnCode (*p)(const void*, size_t, NSObjectFileImage*) = NULL;
 
        if(p == NULL)
@@ -420,6 +427,7 @@ NSObjectFileImage *objectFileImage)
        return p(address, size, objectFileImage);
 }
 
+#if OBSOLETE_DYLD_API
 /*
  * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the 
  * specified core file name if the file is a correct Mach-O core file.
@@ -431,19 +439,20 @@ NSCreateCoreFileImageFromFile(
 const char* pathName,
 NSObjectFileImage *objectFileImage)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSObjectFileImageReturnCode (*p)(const char*, NSObjectFileImage*) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_NSCreateCoreFileImageFromFile", (void**)&p);
        return p(pathName, objectFileImage);
 }
+#endif
 
 bool
 NSDestroyObjectFileImage(
 NSObjectFileImage objectFileImage)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(NSObjectFileImage) = NULL;
 
        if(p == NULL)
@@ -458,7 +467,7 @@ NSObjectFileImage objectFileImage,
 const char* moduleName,
 uint32_t options)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static NSModule (*p)(NSObjectFileImage, const char*, unsigned long) = NULL;
 
        if(p == NULL)
@@ -485,7 +494,7 @@ const char** segmentName,   /* can be NULL */
 const char** sectionName,      /* can be NULL */
 unsigned long* sectionOffset)  /* can be NULL */
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(NSObjectFileImage, unsigned long, const char**, const char**, unsigned long*) = NULL;
 
        if(p == NULL)
@@ -503,7 +512,7 @@ uint32_t
 NSSymbolDefinitionCountInObjectFileImage(
 NSObjectFileImage objectFileImage)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static unsigned long (*p)(NSObjectFileImage) = NULL;
 
        if(p == NULL)
@@ -523,7 +532,7 @@ NSSymbolDefinitionNameInObjectFileImage(
 NSObjectFileImage objectFileImage,
 uint32_t ordinal)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const char*  (*p)(NSObjectFileImage, uint32_t) = NULL;
 
        if(p == NULL)
@@ -540,7 +549,7 @@ uint32_t
 NSSymbolReferenceCountInObjectFileImage(
 NSObjectFileImage objectFileImage)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static unsigned long (*p)(NSObjectFileImage) = NULL;
 
        if(p == NULL)
@@ -561,7 +570,7 @@ NSObjectFileImage objectFileImage,
 uint32_t ordinal,
 bool *tentative_definition) /* can be NULL */
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const char*  (*p)(NSObjectFileImage, uint32_t, bool*) = NULL;
 
        if(p == NULL)
@@ -579,7 +588,7 @@ NSIsSymbolDefinedInObjectFileImage(
 NSObjectFileImage objectFileImage,
 const char* symbolName)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(NSObjectFileImage, const char*) = NULL;
 
        if(p == NULL)
@@ -602,7 +611,7 @@ const char* segmentName,
 const char* sectionName,
 unsigned long *size) /* can be NULL */
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void* (*p)(NSObjectFileImage, const char*, const char*, unsigned long*) = NULL;
 
        if(p == NULL)
@@ -621,7 +630,7 @@ bool
 NSHasModInitObjectFileImage(
 NSObjectFileImage objectFileImage)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(NSObjectFileImage) = NULL;
 
        if(p == NULL)
@@ -637,7 +646,7 @@ int *errorNumber,
 const char* *fileName,
 const char* *errorString)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(NSLinkEditErrors *c,
                     int *errorNumber, 
                     const char* *fileName,
@@ -654,7 +663,7 @@ NSUnLinkModule(
 NSModule module, 
 uint32_t options)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(NSModule module, uint32_t options) = NULL;
 
        if(p == NULL)
@@ -663,6 +672,7 @@ uint32_t options)
        return p(module, options);
 }
 
+#if OBSOLETE_DYLD_API
 NSModule
 NSReplaceModule(
 NSModule moduleToReplace,
@@ -671,6 +681,7 @@ uint32_t options)
 {
        return(NULL);
 }
+#endif
 
 /*
  *_NSGetExecutablePath copies the path of the executable into the buffer and
@@ -686,7 +697,7 @@ _NSGetExecutablePath(
 char *buf,
 uint32_t *bufsize)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static int (*p)(char *buf, uint32_t *bufsize) = NULL;
 
        if(p == NULL)
@@ -700,7 +711,7 @@ const char* symbol_name,
 void** address,
 NSModule* module)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(const char*, void** , NSModule*) = NULL;
 
        if(p == NULL)
@@ -715,7 +726,7 @@ const char* library_name_hint,
 void** address,
 NSModule* module)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(const char*, const char*, void**, NSModule*) = NULL;
 
        if(p == NULL)
@@ -723,19 +734,21 @@ NSModule* module)
        p(symbol_name, library_name_hint, address, module);
 }
 
+#if OBSOLETE_DYLD_API
 void
 _dyld_lookup_and_bind_objc(
 const char* symbol_name,
 void** address,
 NSModule* module)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(const char* , void**, NSModule*) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_lookup_and_bind_objc", (void**)&p);
        p(symbol_name, address, module);
 }
+#endif
 
 void
 _dyld_lookup_and_bind_fully(
@@ -743,7 +756,7 @@ const char* symbol_name,
 void** address,
 NSModule* module)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(const char*, void**, NSModule*) = NULL;
 
        if(p == NULL)
@@ -755,7 +768,7 @@ bool
 _dyld_bind_fully_image_containing_address(
 const void* address)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const void*) = NULL;
 
        if(p == NULL)
@@ -774,7 +787,7 @@ void
 _dyld_register_func_for_add_image(
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL;
 
        if(p == NULL)
@@ -791,7 +804,7 @@ void
 _dyld_register_func_for_remove_image(
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL;
 
        if(p == NULL)
@@ -799,6 +812,7 @@ void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
        p(func);
 }
 
+#if OBSOLETE_DYLD_API
 /*
  * _dyld_register_func_for_link_module registers the specified function to be
  * called when a module is bound into the program.  When this function is first
@@ -809,7 +823,7 @@ void
 _dyld_register_func_for_link_module(
 void (*func)(NSModule module))
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*func)(NSModule module)) = NULL;
 
        if(p == NULL)
@@ -825,7 +839,7 @@ void
 _dyld_register_func_for_unlink_module(
 void (*func)(NSModule module))
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*func)(NSModule module)) = NULL;
 
        if(p == NULL)
@@ -841,7 +855,7 @@ void
 _dyld_register_func_for_replace_module(
 void (*func)(NSModule oldmodule, NSModule newmodule))
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*func)(NSModule oldmodule,
                                  NSModule newmodule)) = NULL;
 
@@ -862,7 +876,7 @@ NSModule module,
 void **objc_module,
 unsigned long *size)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(NSModule module,
                     void **objc_module,
                     unsigned long *size) = NULL;
@@ -878,45 +892,37 @@ unsigned long *size)
  * to be bound.
  */
 void
-_dyld_bind_objc_module(
-const void* objc_module)
+_dyld_bind_objc_module(const void* objc_module)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(const void *objc_module) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_bind_objc_module", (void**)&p);
        p(objc_module);
 }
+#endif
 
-
-#if __DYNAMIC__
 bool
-_dyld_present(
-void)
+_dyld_present(void)
 {
-       // hmmm, this code is in libSystem.dylib, which is loaded by dyld...
+       // this function exists for compatiblity only
        return true;
 }
-#endif
 
 uint32_t
-_dyld_image_count(
-void)
+_dyld_image_count(void)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
     static unsigned long (*p)(void) = NULL;
 
-       if(_dyld_present() == 0)
-           return(0);
        if(p == NULL)
            _dyld_func_lookup("__dyld_image_count", (void**)&p);
        return(p());
 }
 
 const struct mach_header *
-_dyld_get_image_header(
-uint32_t image_index)
+_dyld_get_image_header(uint32_t image_index)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
     static struct mach_header * (*p)(uint32_t image_index) = NULL;
@@ -927,8 +933,7 @@ uint32_t image_index)
 }
 
 intptr_t
-_dyld_get_image_vmaddr_slide(
-uint32_t image_index)
+_dyld_get_image_vmaddr_slide(uint32_t image_index)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
     static unsigned long (*p)(uint32_t image_index) = NULL;
@@ -939,8 +944,7 @@ uint32_t image_index)
 }
 
 const char* 
-_dyld_get_image_name(
-uint32_t image_index)
+_dyld_get_image_name(uint32_t image_index)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
     static const char*  (*p)(uint32_t image_index) = NULL;
@@ -951,10 +955,9 @@ uint32_t image_index)
 }
 
 bool
-_dyld_image_containing_address(
-const void* address)
+_dyld_image_containing_address(const void* address)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(const void*) = NULL;
 
        if(p == NULL)
@@ -966,7 +969,7 @@ const struct mach_header *
 _dyld_get_image_header_containing_address(
 const void* address)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static const struct mach_header * (*p)(const void*) = NULL;
 
        if(p == NULL)
@@ -977,7 +980,7 @@ const void* address)
 void _dyld_moninit(
 void (*monaddition)(char *lowpc, char *highpc))
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void (*p)(void (*monaddition)(char *lowpc, char *highpc)) = NULL;
 
        if(p == NULL)
@@ -985,10 +988,9 @@ void (*monaddition)(char *lowpc, char *highpc))
        p(monaddition);
 }
 
-bool _dyld_launched_prebound(
-void)
+bool _dyld_launched_prebound(void)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(void) = NULL;
 
        if(p == NULL)
@@ -996,10 +998,9 @@ void)
        return(p());
 }
 
-bool _dyld_all_twolevel_modules_prebound(
-void)
+bool _dyld_all_twolevel_modules_prebound(void)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static bool (*p)(void) = NULL;
 
        if(p == NULL)
@@ -1013,11 +1014,14 @@ void)
 #include <pthread.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
-#include "dyldLock.h"
-#include "dyldLibSystemThreadHelpers.h"
+#include <servers/bootstrap.h>
+#include "dyldLibSystemInterface.h"
+#include "dyld_shared_cache_user.h"
+
 
 // pthread key used to access per-thread dlerror message
 static pthread_key_t dlerrorPerThreadKey;
+static bool dlerrorPerThreadKeyInitialized = false;
 
 // data kept per-thread
 struct dlerrorPerThreadData
@@ -1029,6 +1033,13 @@ struct dlerrorPerThreadData
 // function called by dyld to get buffer to store dlerror message
 static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
 {
+       // ok to create key lazily because this function is called within dyld lock, so there is no race condition
+       if (!dlerrorPerThreadKeyInitialized ) {
+               // create key and tell pthread package to call free() on any data associated with key if thread dies
+               pthread_key_create(&dlerrorPerThreadKey, &free);
+               dlerrorPerThreadKeyInitialized = true;
+       }
+
        const int size = (sizeRequired < 256) ? 256 : sizeRequired;
        dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey);
        if ( data == NULL ) {
@@ -1049,37 +1060,77 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
        return data->message;
 }
 
+
+
+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
+
+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);
+}
+
+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);
+}
+
+
+
 // that table passed to dyld containing thread helpers
-static dyld::ThreadingHelpers sThreadHelpers = { 1, &lockForLazyBinding, &unlockForLazyBinding, &getPerThreadBufferFor_dlerror };
+static dyld::LibSystemHelpers sHelpers = { 4, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
+                                                                       &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
+                                                                       &shared_cache_missing, &shared_cache_out_of_date,
+                                                                       NULL, NULL };
+
 
 //
 // during initialization of libSystem this routine will run
-// and call dyld, registering the threading helpers.
-//
+// and call dyld, registering the helper functions.
 //
-static int registerWithDyld()
+extern "C" void _dyld_initializer() __attribute__((visibility("hidden")));
+void _dyld_initializer()
 {
-    static void (*p)(dyld::ThreadingHelpers*) = NULL;
-
-       // create key and tell pthread package to call free() on any data associated with key if thread dies
-       pthread_key_create(&dlerrorPerThreadKey, &free);
+       DYLD_LOCK_INITIALIZER;
        
-       if(p == NULL) 
-           _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p);
+   void (*p)(dyld::LibSystemHelpers*);
+
+       _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p);
        if(p != NULL)
-               p(&sThreadHelpers);
-       
-       return 0;
+               p(&sHelpers);
 }
 
-// should be able to use __attribute__((constructor)) on registerWithDyld, but compiler has bug (3679135)
-// instead use initialization of global to force it to run.
-static int hack = registerWithDyld();
-
 
 char* dlerror()
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static char* (*p)() = NULL;
 
        if(p == NULL)
@@ -1089,7 +1140,7 @@ char* dlerror()
 
 int dladdr(const void* addr, Dl_info* info)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static int (*p)(const void* , Dl_info*) = NULL;
 
        if(p == NULL)
@@ -1099,7 +1150,7 @@ int dladdr(const void* addr, Dl_info* info)
 
 int dlclose(void* handle)
 {
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static int (*p)(void* handle) = NULL;
 
        if(p == NULL)
@@ -1108,18 +1159,36 @@ int dlclose(void* handle)
 }
 
 void* dlopen(const char* path, int mode)
-{
-       DYLD_WRITER_LOCK_THIS_BLOCK;
+{      
+       // dlopen is special. locking is done inside dyld to allow initializer to run without lock
+       DYLD_NO_LOCK_THIS_BLOCK;
+       
     static void* (*p)(const char* path, int) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_dlopen", (void**)&p);
-       return(p(path, mode));
+       void* result = p(path, mode);
+       // use asm block to prevent tail call optimization
+       // this is needed because dlopen uses __builtin_return_address() and depends on this glue being in the frame chain
+       // <rdar://problem/5313172 dlopen() looks too far up stack, can cause crash>
+       __asm__ volatile(""); 
+       
+       return result;
+}
+
+bool dlopen_preflight(const char* path)
+{
+       DYLD_LOCK_THIS_BLOCK;
+    static bool (*p)(const char* path) = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_dlopen_preflight", (void**)&p);
+       return(p(path));
 }
 
 void* dlsym(void* handle, const char* symbol)
 {
-       DYLD_READER_LOCK_THIS_BLOCK;
+       DYLD_LOCK_THIS_BLOCK;
     static void* (*p)(void* handle, const char* symbol) = NULL;
 
        if(p == NULL)
@@ -1127,6 +1196,17 @@ void* dlsym(void* handle, const char* symbol)
        return(p(handle, symbol));
 }
 
+void dyld_register_image_state_change_handler(dyld_image_states state, 
+                                                                                       bool batch, dyld_image_state_change_handler handler)
+{
+       DYLD_LOCK_THIS_BLOCK;
+    static void* (*p)(dyld_image_states, bool, dyld_image_state_change_handler) = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_dyld_register_image_state_change_handler", (void**)&p);
+       p(state, batch, handler);
+}
+
 
 
 
index ea022cc16938483a1befa448cdbf973084275b76..133e978fe2710d8bc926c5caca09b31a90fb5fae 100644 (file)
@@ -24,8 +24,8 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <mach-o/loader.h>
+#include <unistd.h>
 
 //
 // BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
@@ -98,8 +98,8 @@ const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
 static __attribute__((noreturn)) 
 void dyld_abort() 
 {
-       fprintf(stderr, "internal dyld error\n");
-       abort();
+       //dyld::log("internal dyld error\n");
+       _exit(1);
 }
 
 void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
index a4e8cc331ac84e71bf91f28f07e413feb0900b04..61b23b38d7b03e8881369342c1dae37553a38bd0 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
 #include <stddef.h>
 #include <string.h>
+#include <stdlib.h>
 #include <mach/mach.h>
 #include <mach-o/loader.h>
 #include <mach-o/ldsyms.h>
 #endif
 #include "dyld.h"
 
+#ifndef MH_PIE
+       #define MH_PIE 0x200000 
+#endif
+
+
 #if __LP64__
        #define macho_header                    mach_header_64
        #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
        #define POINTER_RELOC GENERIC_RELOC_VANILLA
 #endif
 
+// from dyld.cpp
+namespace dyld { extern bool isRosetta(); };
+
+
 //
 //  Code to bootstrap dyld into a runnable state
 //
@@ -194,7 +206,7 @@ static void segmentProtectDyld(const struct macho_header* mh, intptr_t slide)
                                        vm_size_t size = seg->vmsize;
                                        const bool setCurrentPermissions = false;
                                        vm_protect(mach_task_self(), addr, size, setCurrentPermissions, seg->initprot);
-                                       //fprintf(stderr, "dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot);
+                                       //dyld::log("dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot);
                                }
                                break;
                }
@@ -203,9 +215,114 @@ 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)
+{
+#if __ppc__
+       // don't slide PIE programs running under rosetta
+       if ( dyld::isRosetta() )
+               return orgMH;
+#endif
+       // count segments
+       uint32_t segCount = 0;
+       const uint32_t cmd_count = orgMH->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)orgMH)+sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
+                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
+                       // page-zero and custom stacks don't move
+                       if ( (strcmp(segCmd->segname, "__PAGEZERO") != 0) && (strcmp(segCmd->segname, "__UNIXSTACK") != 0) ) 
+                               ++segCount;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // make copy of segment info
+       macho_segment_command segs[segCount];
+       uint32_t index = 0;
+       uintptr_t highestAddressUsed = 0;
+       uintptr_t lowestAddressUsed = UINTPTR_MAX;
+       cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
+                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
+                       if ( (strcmp(segCmd->segname, "__PAGEZERO") != 0) && (strcmp(segCmd->segname, "__UNIXSTACK") != 0) ) {
+                               segs[index++] = *segCmd;
+                               if ( (segCmd->vmaddr + segCmd->vmsize) > highestAddressUsed )
+                                       highestAddressUsed = ((segCmd->vmaddr + segCmd->vmsize) + 4095) & -4096;
+                               if ( segCmd->vmaddr < lowestAddressUsed )
+                                       lowestAddressUsed = segCmd->vmaddr;
+                               // do nothing if kernel has already randomized load address
+                               if ( (strcmp(segCmd->segname, "__TEXT") == 0) && (segCmd->vmaddr != (uintptr_t)orgMH) )
+                                       return orgMH;
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // choose a random new base address
+#if __LP64__
+       uintptr_t highestAddressPossible = highestAddressUsed + 0x100000000ULL;
+#else
+       uintptr_t highestAddressPossible = 0x80000000;
+#endif
+       uintptr_t sizeNeeded = highestAddressUsed-lowestAddressUsed;
+       if ( (highestAddressPossible-sizeNeeded) < highestAddressUsed ) {
+               // new and old segments will overlap 
+               // need better algorithm for remapping
+               // punt and don't re-map
+               return orgMH;
+       }
+       uintptr_t possibleRange = (highestAddressPossible-sizeNeeded) - highestAddressUsed;
+       uintptr_t newBaseAddress = highestAddressUsed + ((arc4random() % possibleRange) & -4096);
+       
+       vm_address_t addr = newBaseAddress;
+       // reserve new address range
+       if ( vm_allocate(mach_task_self(), &addr, sizeNeeded, VM_FLAGS_FIXED) == KERN_SUCCESS ) {
+               // copy each segment to new address
+               for (uint32_t i = 0; i < segCount; ++i) {
+                       uintptr_t newSegAddress = segs[i].vmaddr - lowestAddressUsed + newBaseAddress;
+                       if ( (vm_copy(mach_task_self(), segs[i].vmaddr, segs[i].vmsize, newSegAddress) != KERN_SUCCESS)
+                               || (vm_protect(mach_task_self(), newSegAddress, segs[i].vmsize, true, segs[i].maxprot) != KERN_SUCCESS) 
+                               || (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");
+                               return orgMH;
+                       }
+               }
+               // unmap original segments
+               vm_deallocate(mach_task_self(), lowestAddressUsed, highestAddressUsed-lowestAddressUsed);
+       
+               // run with newly mapped executable
+               *appsSlide = newBaseAddress - lowestAddressUsed;
+               return (const struct mach_header*)newBaseAddress;
+       }
+       
+       // can't get new range, so don't slide to random address
+       return orgMH;
+}
+
+
 extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp
 extern "C" void mach_init();
 
+//
+// _pthread_keys is partitioned in a lower part that dyld will use; libSystem
+// will use the upper part.  We set __pthread_tsd_first to 1 as the start of
+// the lower part.  Libc will take #1 and c++ exceptions will take #2.  There
+// is one free key=3 left.
+//
+extern "C" {
+       extern int __pthread_tsd_first;
+       extern void _pthread_keys_init();
+}
+
+
 //
 //  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.
@@ -221,6 +338,12 @@ uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char*
                rebaseDyld(dyldsMachHeader, slide);
        }
        
+       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);
        
@@ -241,8 +364,12 @@ uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char*
        // run all C++ initializers inside dyld
        runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple);
        
+       // if main executable was linked -pie, then randomize its load address
+       if ( appsMachHeader->flags & MH_PIE )
+               appsMachHeader = randomizeExecutableLoadAddress(appsMachHeader, &appsSlide);
+       
        // now that we are done bootstrapping dyld, call dyld's main
-       return dyld::_main(appsMachHeader, argc, argv, envp, apple);
+       return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple);
 }
 
 
diff --git a/src/dyldLibSystemInterface.h b/src/dyldLibSystemInterface.h
new file mode 100644 (file)
index 0000000..c110616
--- /dev/null
@@ -0,0 +1,62 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004-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@
+ */
+
+
+#ifndef __DYLDLIBSYSTEMHELPERS__
+#define __DYLDLIBSYSTEMHELPERS__
+
+#include <stdint.h>
+
+
+namespace dyld {
+       //
+       // This file contains the synchronization utilities used by dyld to be thread safe.
+       // This struct is implemented in in libSystem (where pthreads is available)
+       // and passed to dyld to use.
+       //
+       struct LibSystemHelpers
+       {
+               uintptr_t       version;
+               void            (*acquireGlobalDyldLock)();
+               void            (*releaseGlobalDyldLock)();
+               char*           (*getThreadBufferFor_dlerror)(uint32_t sizeRequired);
+               // addded in version 2
+               void*           (*malloc)(size_t);
+               void            (*free)(void*);
+               int                     (*cxa_atexit)(void (*)(void*), void*, void*);
+               // addded in version 3
+               void            (*dyld_shared_cache_missing)();
+               void            (*dyld_shared_cache_out_of_date)();
+               // addded in version 4
+               void            (*acquireDyldInitializerLock)();
+               void            (*releaseDyldInitializerLock)();
+       };
+};
+
+
+
+
+
+#endif // __DYLDLIBSYSTEMHELPERS__
+
diff --git a/src/dyldLibSystemThreadHelpers.h b/src/dyldLibSystemThreadHelpers.h
deleted file mode 100644 (file)
index ac5e3dc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2004-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@
- */
-
-
-#ifndef __DYLDLIBSYSTEMHELPERS__
-#define __DYLDLIBSYSTEMHELPERS__
-
-#include <stdint.h>
-
-
-namespace dyld {
-       //
-       // This file contains the synchronization utilities used by dyld to be thread safe.
-       // This struct is implemented in in libSystem (where pthreads is available)
-       // and passed to dyld to use.
-       //
-       struct ThreadingHelpers
-       {
-               uintptr_t       version;
-               void            (*lockForReading)();
-               void            (*unlockForReading)();
-               char*           (*getThreadBufferFor_dlerror)(uint32_t sizeRequired);
-       };
-};
-
-
-
-
-
-#endif // __DYLDLIBSYSTEMHELPERS__
-
index 496ed92f4e8c14b2c6277b5c82390d569e748d21..b94551b3c79f7d61bdfd06ce7f2c87dff68d3536 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "dyldLock.h"
 
-// until the reader/writer locks are fully tested, we just use a simple recursive mutex
-#define REAL_READER_WRITER_LOCK 0
 
 
-
-//
-// This class implements a recursive reader/writer lock.
-// Recursive means a thread that has already aquired the lock can re-acquire it.
-// The lock allows either:
-//      a) one "writer" thread to hold lock
-//             b) multiple "reader" threads to hold
-//
-// A thread with the writer can acquire a reader lock.
-// A thread with a reader lock can acquire a writer lock iff it is the only thread with a reader lock
-//
-class RecursiveReaderWriterLock 
-{
-public:
-                       RecursiveReaderWriterLock() __attribute__((visibility("hidden")));
-       void    initIfNeeded();
-       
-       
-       void    lockForSingleWritingThread() __attribute__((visibility("hidden")));
-       void    unlockForSingleWritingThread() __attribute__((visibility("hidden")));
-       
-       void    lockForMultipleReadingThreads() __attribute__((visibility("hidden")));
-       void    unlockForMultipleReadingThreads() __attribute__((visibility("hidden")));
-
-private:
-#if REAL_READER_WRITER_LOCK
-       struct ThreadRecursionCount {
-               pthread_t       fThread;
-               uint32_t        fCount;
-       };
-       bool    writerThreadIsAnyThreadBut(pthread_t thread);
-       void    writerThreadRetain(pthread_t thread);
-       bool    writerThreadRelease(pthread_t thread);
-
-       enum { kMaxReaderThreads = 4 };
-       bool    readerThreadSetRetain(pthread_t thread);
-       bool    readerThreadSetRelease(pthread_t thread);
-       bool    readerThreadSetContainsAnotherThread(pthread_t thread);
-
-       ThreadRecursionCount    fWriterThread;
-       ThreadRecursionCount    fReaderThreads[kMaxReaderThreads];
-       pthread_cond_t                  fLockFree;
-       pthread_mutex_t                 fMutex;
-#else
-       pthread_mutex_t                 fMutex;
-#endif
-       bool                                    fInitialized;   // assumes this is statically initialized to false because sLock is static
-};
+static pthread_mutex_t sGlobalMutex;
 
 
 //
-// initIfNeeded() is a hack so that when libSystem_debug.dylb is useable.
-// The problem is that Objective-C +load methods are called before C++ initialziers are run
-// If +load method makes a call into dyld, sLock is not initialized.  
+// This initializer can go away once the following is available:
+//     <rdar://problem/4927311> implement PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 //
-// The long term solution is for objc and dyld to work more closely together so that instead
-// of running all +load methods before all initializers, we run each image's +load then its
-// initializers all in bottom up order.
-//
-// This lazy initialization is not thread safe, but as long as someone does not create a 
-// new thread in a +load method, the C++ constructor for sLock will be called before main()
-// so there will only be one thead.
-//
-void RecursiveReaderWriterLock::initIfNeeded()
-{
-       if ( ! fInitialized ) {
-               pthread_mutexattr_t recursiveMutexAttr;
-               pthread_mutexattr_init(&recursiveMutexAttr);
-               pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
-               pthread_mutex_init(&fMutex, &recursiveMutexAttr);
-       #if REAL_READER_WRITER_LOCK
-               pthread_cond_init(&fLockFree, NULL);
-               fWriterThread.fThread = NULL;
-               fWriterThread.fCount = 0;
-               for (int i=0; i < kMaxReaderThreads; ++i) {
-                       fReaderThreads[i].fThread = NULL;
-                       fReaderThreads[i].fCount = 0;
-               }
-       #endif
-               fInitialized = true;
-       }
-}
-
-RecursiveReaderWriterLock::RecursiveReaderWriterLock()
-{
-       initIfNeeded();
-}
-
-void RecursiveReaderWriterLock::lockForSingleWritingThread()
-{
-       this->initIfNeeded();
-#if REAL_READER_WRITER_LOCK
-       pthread_mutex_lock(&fMutex);
-       pthread_t thisThread = pthread_self();
-       // wait as long as there is another writer or any readers on a different thread
-       while ( writerThreadIsAnyThreadBut(thisThread) || readerThreadSetContainsAnotherThread(thisThread) ) {
-               pthread_cond_wait(&fLockFree, &fMutex);
-       }
-       writerThreadRetain(thisThread);
-       pthread_mutex_unlock(&fMutex);
-#else
-       pthread_mutex_lock(&fMutex);
-#endif
-}
-
-void RecursiveReaderWriterLock::unlockForSingleWritingThread()
-{
-       this->initIfNeeded();
-#if REAL_READER_WRITER_LOCK
-       pthread_mutex_lock(&fMutex);
-       if ( writerThreadRelease(pthread_self()) ) {
-               pthread_cond_broadcast(&fLockFree);
-       }
-       pthread_mutex_unlock(&fMutex);
-#else
-       pthread_mutex_unlock(&fMutex);
-#endif
-}
-
-
-void RecursiveReaderWriterLock::lockForMultipleReadingThreads()
-{
-       this->initIfNeeded();
-#if REAL_READER_WRITER_LOCK
-       pthread_mutex_lock(&fMutex);
-       pthread_t thisThread = pthread_self();
-       // wait as long as there is a writer on another thread or too many readers already
-       while ( writerThreadIsAnyThreadBut(thisThread) || !readerThreadSetRetain(thisThread) ) {
-               pthread_cond_wait(&fLockFree, &fMutex);
-       }
-       pthread_mutex_unlock(&fMutex);
-#else
-       pthread_mutex_lock(&fMutex);
-#endif
-}
-
-
-void RecursiveReaderWriterLock::unlockForMultipleReadingThreads()
-{
-       this->initIfNeeded();
-#if REAL_READER_WRITER_LOCK
-       pthread_mutex_lock(&fMutex);
-       if ( readerThreadSetRelease(pthread_self()) ) {
-               pthread_cond_broadcast(&fLockFree);
-       }
-       pthread_mutex_unlock(&fMutex);
-#else
-       pthread_mutex_unlock(&fMutex);
-#endif
-}
-
-#if REAL_READER_WRITER_LOCK
-bool RecursiveReaderWriterLock::writerThreadIsAnyThreadBut(pthread_t thread)
-{
-       return ( (fWriterThread.fThread != NULL) && (fWriterThread.fThread != thread) );
-}
-
-void RecursiveReaderWriterLock::writerThreadRetain(pthread_t thread)
+void dyldGlobalLockInitialize()
 {
-       ++fWriterThread.fCount;
+       pthread_mutexattr_t recursiveMutexAttr;
+       pthread_mutexattr_init(&recursiveMutexAttr);
+       pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
+       pthread_mutex_init(&sGlobalMutex, &recursiveMutexAttr);
 }
 
-bool RecursiveReaderWriterLock::writerThreadRelease(pthread_t thread)
-{
-       return ( --fWriterThread.fCount == 0 );
-}
 
-
-bool RecursiveReaderWriterLock::readerThreadSetRetain(pthread_t thread)
-{
-       // if thread is already in set, bump its count
-       for (int i=0; i < kMaxReaderThreads; ++i) {
-               if ( fReaderThreads[i].fThread == thread ) {
-                       ++fReaderThreads[i].fCount;
-                       return true;
-               }
-       }
-       // find empty slot in set
-       for (int i=0; i < kMaxReaderThreads; ++i) {
-               if ( fReaderThreads[i].fThread == NULL ) {
-                       fReaderThreads[i].fThread = thread;
-                       fReaderThreads[i].fCount = 1;
-                       return true;
-               }
-       }
-
-       // all reader slots full
-       return false;
-}
-
-bool RecursiveReaderWriterLock::readerThreadSetRelease(pthread_t thread)
-{
-       for (int i=0; i < kMaxReaderThreads; ++i) {
-               if ( fReaderThreads[i].fThread == thread ) {
-                       if ( --fReaderThreads[i].fCount == 0 ) {
-                               fReaderThreads[i].fThread = NULL;
-                               return true;
-                       }
-                       return false;
-               }
-       }
-       // should never get here
-       return false;
-}
-
-bool RecursiveReaderWriterLock::readerThreadSetContainsAnotherThread(pthread_t thread)
-{
-       for (int i=0; i < kMaxReaderThreads; ++i) {
-               if ( (fReaderThreads[i].fThread != NULL) && (fReaderThreads[i].fThread != thread) ) 
-                       return true;
-       }
-       return false;
-}
-#endif
-
-
-// dyld's global reader/writer lock
-static RecursiveReaderWriterLock       sLock;
-
-
-LockReaderHelper::LockReaderHelper() 
-{ 
-       sLock.lockForMultipleReadingThreads();
-}
-
-LockReaderHelper::~LockReaderHelper() 
+LockHelper::LockHelper() 
 { 
-       sLock.unlockForMultipleReadingThreads();
+       pthread_mutex_lock(&sGlobalMutex);
 }
 
-
-LockWriterHelper::LockWriterHelper() 
+LockHelper::~LockHelper() 
 { 
-       sLock.lockForSingleWritingThread();
+       pthread_mutex_unlock(&sGlobalMutex);
 }
 
-LockWriterHelper::~LockWriterHelper() 
-{ 
-       sLock.unlockForSingleWritingThread();
-}
-
-
-// needed by lazy binding
-void lockForLazyBinding() 
+void dyldGlobalLockAcquire() 
 {
-       sLock.lockForMultipleReadingThreads();
+       pthread_mutex_lock(&sGlobalMutex);
 }
 
-void unlockForLazyBinding() 
+void dyldGlobalLockRelease() 
 {
-       sLock.unlockForMultipleReadingThreads();
+       pthread_mutex_unlock(&sGlobalMutex);
 }
 
 
-
index d6291fbb5a7cebb99347dfd162baf9d10c1a56f8..2f4ec59edeed49978a050ae2469be91fa95c03fe 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define __DYLDLOCK__
 
 //
-// This file contains the syncronization utilities used by dyld to be thread safe.
-// Access to all dyld data structures is protected by a reader-writer lock.
-// This lock allows multiple "reader" threads to access dyld data structures at
-// the same time.  If there is a "writer" thread, it is the only thread allowed
-// access to dyld data structures.  
+// This file contains the synchronization utilities used to make dyld APIs be thread safe.
 //
-// The implementation of all dyld API's must acquire the global lock around accesses
-// to dyld's data structures.  This is done using the macros DYLD_*_LOCK_THIS_BLOCK.
+// The implementation of all dyld API's must hold acquire global lock (in libSystem)
+// before calling into dyld proper, and release the lock after returning from dyld.
+// This is done using the macros DYLD_LOCK_THIS_BLOCK.
 // Example:
 //
-//  void dyld_api_modifying_dyld() {
-//             DYLD_WRITER_LOCK_THIS_BLOCK;
+//  void dyld_api() {
+//             DYLD_LOCK_THIS_BLOCK;
 //             // free to do stuff here 
-//             // that modifies dyld data structures
-//     }
-//
-//  void dyld_api_examinging_dyld() {
-//             DYLD_READER_LOCK_THIS_BLOCK
-//             // can only do stuff here 
-//             // that examines but does not modify dyld data structures
+//             // that accesses dyld internal data structures
 //     }
 //
 //  void dyld_api_state_free() {
 //     }
 //
 
-
-#define DYLD_READER_LOCK_THIS_BLOCK            LockReaderHelper _dyld_lock;
-#define DYLD_WRITER_LOCK_THIS_BLOCK            LockWriterHelper _dyld_lock;
+#define DYLD_LOCK_INITIALIZER                  dyldGlobalLockInitialize()
+#define DYLD_LOCK_THIS_BLOCK                   LockHelper _dyld_lock;
 #define DYLD_NO_LOCK_THIS_BLOCK
 
 // used by dyld wrapper functions in libSystem
-class LockReaderHelper
-{
-public:
-       LockReaderHelper() __attribute__((visibility("hidden")));
-       ~LockReaderHelper() __attribute__((visibility("hidden")));
-};
-
-// used by dyld wrapper functions in libSystem
-class LockWriterHelper
+class __attribute__((visibility("hidden"))) LockHelper
 {
 public:
-       LockWriterHelper() __attribute__((visibility("hidden")));
-       ~LockWriterHelper() __attribute__((visibility("hidden")));
+       LockHelper();
+       ~LockHelper();
 };
 
-// used by lazy binding
-extern void lockForLazyBinding() __attribute__((visibility("hidden")));
-extern void unlockForLazyBinding() __attribute__((visibility("hidden")));
-
 
+// to initialize
+extern void dyldGlobalLockInitialize()         __attribute__((visibility("hidden")));
+extern void dyldGlobalLockAcquire()                    __attribute__((visibility("hidden")));
+extern void dyldGlobalLockRelease()                    __attribute__((visibility("hidden")));
 
 #endif // __DYLDLOCK__
 
index a74d8586495c29121b073c3e8454a3a124bfa84e..4a5dcad48f7bcbeaefc5a5e2c816d66ccfa5a79b 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include <new>
-#include <malloc/malloc.h>
-//#include <stdio.h>
 
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" void* __dso_handle;
+
+#include "dyld.h"
+#include "dyldLibSystemInterface.h"
 
 //
-// dyld does not use malloc anywhere, instead C++ new is used.
-// All dyld allocations go in dyld-only zone so as to be not co-mingled with target proccess's allocations
-//
-//
+//      dyld initially allocates all memory from a pool inside dyld.
+//   Once libSystem.dylib is initialized, dyld uses libSystem's malloc/free.
 //
 
-static malloc_zone_t* sZone = NULL;  // could be initialized to malloc_create_zone, but that would require careful ordering of initializers
-
+#if __LP64__
+       // room for about ~1000 initial dylibs
+       #define DYLD_INITIAL_POOL_SIZE 400*1024
+#else
+       // room for about ~900 initial dylibs
+       #define DYLD_INITIAL_POOL_SIZE 200*1024
+#endif
+static uint8_t dyldPool[DYLD_INITIAL_POOL_SIZE];
+static uint8_t* curPoolPtr = dyldPool;
 
-void* operator new(std::size_t len) throw (std::bad_alloc)
+void* malloc(size_t size)
 {
-       if ( sZone == NULL ) {
-               sZone = malloc_create_zone(40960, 0);
-               malloc_set_zone_name(sZone, "dyld heap");
+       if ( dyld::gLibSystemHelpers != NULL) {
+               void* p = dyld::gLibSystemHelpers->malloc(size);
+               //dyld::log("malloc(%lu) => %p from libSystem\n", size, p);
+               return p;
+       }
+       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);
+               }
+               curPoolPtr += size;
+               //dyld::log("%p = malloc(%lu) from pool, total = %d\n", result, size, curPoolPtr-dyldPool);
+               return result;
        }
-       //fprintf(stderr, "new(%d)\n", len);
-       return malloc_zone_malloc(sZone, len);
 }
 
-void* operator new[](std::size_t len) throw (std::bad_alloc)
+
+void free(void* ptr)
 {
-       if ( sZone == NULL ) {
-               sZone = malloc_create_zone(40960, 0);
-               malloc_set_zone_name(sZone, "dyld heap");
+       // 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])) ) {
+               //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);
        }
-       //fprintf(stderr, "new[](%d)\n", len);
-       return malloc_zone_malloc(sZone, len);
 }
 
 
-void operator delete(void* obj) throw()
+void* calloc(size_t count, size_t size)
 {
-       //fprintf(stderr, "delete(%p)\n", obj);
-       malloc_zone_free(sZone, obj);
+       if ( dyld::gLibSystemHelpers != NULL ) {
+               void* result = dyld::gLibSystemHelpers->malloc(size);
+               bzero(result, size);
+               return result;
+       }
+       else {
+               return malloc(count*size);
+       }
 }
 
 
-void operator delete[](void* obj) throw()
+void* realloc(void *ptr, size_t size)
 {
-       //fprintf(stderr, "delete[](%p)\n", obj);
-       malloc_zone_free(sZone, obj);
+       void* result = malloc(size);
+       memcpy(result, ptr, size);
+       return result;
 }
 
+//     void* reallocf(void *ptr, size_t size);
+//     void* valloc(size_t size);
+
+// needed __libc_init()
+extern "C" int _malloc_lock;
+int _malloc_lock = 0;
+
 
index 2afa8d43e651a3592caa378e7a6a45006f97e3a2..1bf79318ccc2aaf644220839f25cc82ed1096589 100644 (file)
@@ -113,7 +113,7 @@ L__dyld_start_picbase:
        addl    $8,%esp         # remove the mh argument, and debugger end
                                #  frame marker
        movl    $0,%ebp         # restore ebp back to zero
-       jmp     %eax            # jump to the entry point
+       jmp     *%eax           # jump to the entry point
 
 
        .globl dyld_stub_binding_helper
@@ -164,6 +164,7 @@ __dyld_start:
        addq    $16,%rsp        # remove the mh argument, and debugger end frame marker
        movq    $0,%rbp         # restore ebp back to zero
        jmp     *%rax           # jump to the entry point
+       
 #endif /* __x86_64__ */
 
 
@@ -234,3 +235,24 @@ L_end:
 #endif /* __ppc__ */
 
 
+/*
+ * dyld calls this function to terminate a process.
+ * It has a label so that CrashReporter can distinguish this
+ * termination from a random crash.  rdar://problem/4764143
+ */
+       .text
+       .align 2
+       .globl  _dyld_fatal_error
+_dyld_fatal_error:
+#if __ppc__ || __ppc64__
+    trap
+#elif __x86_64__ || __i386__
+    int3
+#else
+    #error unknown architecture
+#endif
+
+    
+    
+
+
index 56c4cec5f5ad86be17199dbc259abd4c39da0e3d..632efab9fbe6d579d6e479c77abeb7653f48e974 100644 (file)
@@ -24,7 +24,6 @@
 
 int dummy_dyld_symbol = 1;
 
-#include <stdio.h> 
 #include <stdlib.h>
 
 // The following API's are deprecated.
@@ -164,9 +163,10 @@ void (*func)(struct dyld_debug_error_data *e))
 
 
 
-// Examine a mach_header in another process and determine its slid
+// Examine a mach_header in another process and determine its slide
 static ptrdiff_t slideForHeader(task_port_t target_task, const struct mach_header* otherAddressHeader)
 {
+       ptrdiff_t result = 0;
        const struct mach_header* mh = xprocess_read(target_task, otherAddressHeader, 0x2000);
        if ( mh != NULL ) {
                int i;
@@ -176,14 +176,15 @@ static ptrdiff_t slideForHeader(task_port_t target_task, const struct mach_heade
                for (i = 0; i < mh->ncmds; i++){
                        if (sgp->cmd == LC_SEGMENT) {
                                if (sgp->fileoff == 0  &&  sgp->filesize != 0) {
-                                       return (uintptr_t)mh - (uintptr_t)sgp->vmaddr;
+                                       result = (uintptr_t)mh - (uintptr_t)sgp->vmaddr;
+                                       break;
                                }
                        }
                        sgp = (const struct segment_command *)((char *)sgp + sgp->cmdsize);
                }
                free((void*)mh);
        }
-       return 0;  
+       return result;  
 }
 
 
index 89a1cd75ad534a27cb754d7bf2882b1b2eb5d259..456f048a8ee86319472b1b08e4771fedd1e5550f 100644 (file)
 #include <vector>
 
 #include "mach-o/dyld_gdb.h"
+#include "mach-o/dyld_images.h"
 
+#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__
 
-// old gdb interface to dyld only supported on 32-bit ppc and i386 (not ppc64_
+// old gdb interface to dyld only supported on 32-bit ppc and i386
 #if OLD_GDB_DYLD_INTERFACE
 
 unsigned int gdb_dyld_version = 2;
@@ -80,8 +82,8 @@ 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 };
+object_images   object_images;// = { {}, 0 , NULL };
+library_images library_images;// = { {}, 0 , NULL };
 void send_event(const struct dyld_event* event);
 }
 
@@ -170,6 +172,10 @@ 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);
+
        // set infoArray to NULL to denote it is in-use
        dyld_all_image_infos.infoArray = NULL;
        
@@ -214,14 +220,17 @@ static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, co
 {
        // do nothing
        // gdb sets a break point here to catch notifications
-       //fprintf(stderr, "dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount);
+       //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount);
+       //for (uint32_t i=0; i < infoCount; ++i)
+       //      dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath);
        //for (uint32_t i=0; i < dyld_all_image_infos.infoArrayCount; ++i)
-       //      fprintf(stderr, "dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath);
+       //      dyld::log("dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath);
 }
 
 
 
 struct dyld_all_image_infos  dyld_all_image_infos = { 1, 0, NULL, &gdb_image_notifier, false };
 
+struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
 
  
index f44e198d36cbf281040b9547f495a204d1ef1982..cce096368f7bf2556d6505dee3c7e937c5ea7f7a 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-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
-#include <notify.h>
 #include <time.h>
+#include <unistd.h>
 
-//
-// Stub functions needed for dyld to link with libc.a instead of libSystem.dylib
-//
-//
-static char* dyld_progname = "dyld";
-
-//
-// libc has calls to _dyld_lookup_and_bind to find args and environment.  Since
-// dyld links with a staic copy of libc, those calls need to find dyld's args and env
-// not the host process.  We implement a special _dyld_lookup_and_bind() that
-// just knows how to bind the few symbols needed by dyld.
-//
-void _dyld_lookup_and_bind(const char* symbolName, void** address, void* module)
+// abort called by C++ unwinding code
+void abort()
 {
-       if ( strcmp(symbolName, "_environ") == 0 ) {
-               // dummy up empty environment list
-               static char *p = NULL;
-               static char **pp = &p;
-               *address = &pp;
-               return;
-       }
-       else if ( strcmp(symbolName, "___progname") == 0 ) {
-               *address = &dyld_progname;
-               return;
-       }
-       
-       fprintf(stderr, "dyld: internal error: unknown symbol '%s'\n", symbolName);
+       _exit(1);
 }
 
-
-int NSIsSymbolNameDefined(const char* symbolName)
+// std::terminate called by C++ unwinding code
+void _ZSt9terminatev()
 {
-       if ( strcmp(symbolName, "___progname") == 0 ) {
-               return 1;
-       }
-       fprintf(stderr, "dyld: internal error: unknown symbol '%s'\n", symbolName);
-       return 0;
+       _exit(1);
 }
 
-
-/*
- * To avoid linking in libm.  These variables are defined as they are used in
- * pthread_init() to put in place a fast sqrt().
- */
-size_t hw_sqrt_len = 0;
-
-double
-sqrt(double x)
+// std::unexpected called by C++ unwinding code
+void _ZSt10unexpectedv()
 {
-       return(0.0);
-}
-double
-hw_sqrt(double x)
-{
-       return(0.0);
+       _exit(1);
 }
 
-/*
- * More stubs to avoid linking in libm.  This works as along as we don't use
- * long doubles.
- */
-long
-__fpclassifyd(double x) 
+// __cxxabiv1::__terminate(void (*)()) called to terminate process
+void _ZN10__cxxabiv111__terminateEPFvvE()
 {
-       return(0);
+       _exit(1);
 }
 
-long
-__fpclassify(long double x)
+// __cxxabiv1::__unexpected(void (*)()) called to terminate process
+void _ZN10__cxxabiv112__unexpectedEPFvvE()
 {
-       return(0);
+       _exit(1);
 }
 
+// __cxxabiv1::__terminate_handler
+void* _ZN10__cxxabiv119__terminate_handlerE  = &_ZSt9terminatev;
 
-char* __hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve)
-{
-       return NULL;
-}
+// __cxxabiv1::__unexpected_handler
+void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
 
-char* __hldtoa(/*long*/ double e, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve)
-{
-       return NULL;
-}
 
-int __fegetfltrounds(void) 
-{
-       return 1;                                       /* FE_NEAREST */
-}
 
-int fegetround(void) 
+
+// real cthread_set_errno_self() has error handling that pulls in 
+// pthread_exit() which pulls in fprintf()
+extern int* __error(void);
+void cthread_set_errno_self(int err)
 {
-       return 1;
+       int* ep = __error();
+     *ep = err;
 }
 
 /*
  * We have our own localtime() to avoid needing the notify API which is used
- * by the code in libc.a for localtime() but is in libnotify.
+ * by the code in libc.a for localtime() which is used by arc4random().
  */
 struct tm* localtime(const time_t* t)
 {
        return (struct tm*)NULL;
 }
 
-struct tm* localtime_r(const time_t* t, struct tm *result)
-{
-       return result;
-}
 
-time_t mktime(struct tm *timeptr)
-{
-       return 0;
-}
-
-
-
-
-/*
- * On ppc64, the C++ runtime references strftime & wcsftime, but they
- * never actually get called, and they try to use all the localtime()
- * machinery, so stub them out.
- */
-
-size_t strftime(char * __restrict p1, size_t p2, const char * __restrict p3,
-                               const struct tm * __restrict p4) 
-{
-       return 0;
-}
-size_t  wcsftime(wchar_t * __restrict p1, size_t p2,
-                                const wchar_t * __restrict p3,
-                                const struct tm * __restrict p4)
-{
-       return 0;
-}
-
-int __strtopdd (const char* p1, char** p2, double* p3)
-{
-       return 0;
-}
-
-char* __ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign, char **rve)
-{
-       return "__ldtoa";
-}
-
-int __hexnan_D2A(const char **sp, void *fpi, unsigned long *x0)
-{
-       return 0;
-}
diff --git a/src/strip.exp b/src/strip.exp
new file mode 100644 (file)
index 0000000..8a2f778
--- /dev/null
@@ -0,0 +1,4 @@
+
+# local symbols to suppress
+*PE*
+*Win*
index 4b13088e127a71e80147592e00d1d088fca6af0d..331a5cd6fabc6656f06c0db625d8f80d4bb627be 100644 (file)
@@ -26,9 +26,8 @@
 #ifdef __i386__
 /*
  * This is the interface for the stub_binding_helper for i386:
- * 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.
+ * The caller has pushed the address of the a lazy pointer to be filled in 
+ * 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
  * Some inter-image function calls pass parameters in registers EAX, ECX, EDX, or XXM0-3,
  * Therefore those registers need to be preserved during the lazy binding.
  * 
- * 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.
+ * After the symbol has been resolved and the lazy pointer filled in, this jumps
+ * to the target address.
  */
-#define MH_PARAM_BP                    4
-#define LP_PARAM_BP                    8
-#define RESULT_BP                      8    /* in order to trash no registers, the target is stored back on the stack then ret it done to it */
-
-#define MH_PARAM_OUT        0
-#define LP_PARAM_OUT        4
-#define EAX_SAVE                       8
-#define ECX_SAVE                       12
-#define EDX_SAVE                       16
-#define XMMM0_SAVE                     32    /* 16-byte align */
-#define XMMM1_SAVE                     48
-#define XMMM2_SAVE                     64
-#define XMMM3_SAVE                     80
-#define STACK_SIZE                     96 /*  (XMMM3_SAVE+16) must be 16 byte aligned too */
-
+#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
 
     .text
     .align 4,0x90
 _fast_stub_binding_helper_interface:
        pushl           $0
     .globl _stub_binding_helper_interface
+    .globl _misaligned_stack_error
 _stub_binding_helper_interface:
-       pushl           %ebp
-       movl            %esp,%ebp
-       subl            $STACK_SIZE,%esp                # at this point stack is 16-byte aligned because two meta-parameters where pushed
-       movl            %eax,EAX_SAVE(%esp)             # save registers that might be used as parameters
+       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)
-       movl            MH_PARAM_BP(%ebp),%eax  # call dyld::bindLazySymbol(mh, lazy_ptr)
+_stub_binding_helper_interface2:
+       movl            MH_LOCAL(%esp),%eax     # call dyld::bindLazySymbol(mh, lazy_ptr)
        movl            %eax,MH_PARAM_OUT(%esp)
-       movl            LP_PARAM_BP(%ebp),%eax
+       movl            LP_LOCAL(%esp),%eax
        movl            %eax,LP_PARAM_OUT(%esp)
        call            __ZN4dyld14bindLazySymbolEPK11mach_headerPm
-       movl            %eax,RESULT_BP(%ebp)    # store target for ret
        movdqa          XMMM0_SAVE(%esp),%xmm0  # restore registers
        movdqa          XMMM1_SAVE(%esp),%xmm1
        movdqa          XMMM2_SAVE(%esp),%xmm2
        movdqa          XMMM3_SAVE(%esp),%xmm3
-       movl            EAX_SAVE(%esp),%eax
        movl            ECX_SAVE(%esp),%ecx
        movl            EDX_SAVE(%esp),%edx
-       addl            $STACK_SIZE,%esp
-       popl            %ebp
-       addl            $4,%esp                                 # remove meta-parameter, other meta-parmaeter now holds target for ret
-       ret
+       movl            %eax,%ebp               # move target address to epb
+       movl            EAX_SAVE(%esp),%eax     # restore eaz
+       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__
 /*
  * This is the interface for the stub_binding_helper for x86_64:
@@ -100,7 +103,7 @@ _stub_binding_helper_interface:
  * 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+8        address of lazy pointer
  * sp+0        address of mach header
  *
  * All parameters registers must be preserved.
@@ -176,6 +179,7 @@ _stub_binding_helper_interface:
 
 #endif
 
+
 #if __ppc__ || __ppc64__
 #include <architecture/ppc/mode_independent_asm.h>
 /*
index 149724fef17c3042b39a18fd99c53e509ac6f1db..f29a1bca6187c341086f7f37730cf607f1eb41ab 100755 (executable)
@@ -21,6 +21,9 @@ sub FAIL
 my $pass_string = shift @ARGV;
 my $fail_string = shift @ARGV;
 
+
+# redirect stderr to stdout
+open(STDERR, ">/tmp/exit-non-zero.tmp") || die("$!");
 if(0 != system(@ARGV))
 {
     PASS($pass_string);
@@ -29,5 +32,12 @@ else
 {
     FAIL($fail_string);
 }
+close(STDERR) || die("$!");
+open(OUT, "</tmp/exit-non-zero.tmp") || die("$!");
+while(<OUT>)
+{
+       print $_;
+}
+close(OUT) || die("$!");
 exit 0;
 
index 54f4b32286b0834a6e03d82f81ef87f6a8f41343..43de2a339aee46439e8fa522dd077b222f6e32af 100755 (executable)
@@ -21,6 +21,8 @@ sub FAIL
 my $pass_string = shift @ARGV;
 my $fail_string = shift @ARGV;
 
+# redirect stderr to stdout
+open(STDERR, ">/tmp/exit-zero-pass.tmp") || die("$!");
 if(0 == system(@ARGV))
 {
     PASS($pass_string);
@@ -29,5 +31,12 @@ else
 {
     FAIL($fail_string);
 }
+close(STDERR) || die("$!");
+open(OUT, "</tmp/exit-zero-pass.tmp") || die("$!");
+while(<OUT>)
+{
+       print $_;
+}
+close(OUT) || die("$!");
 exit 0;
 
index db07357be951c4bae8d22d3d430c8021c6214129..7d6007f393e37bbed19e9ccce77193dcc23d115e 100755 (executable)
@@ -44,7 +44,6 @@ if(length($entry))
 
 # show totals
 my $percentage = $pass_count * 100 / $total_count;
-print "\n";
 printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage;
 
 
@@ -98,17 +97,29 @@ sub process_entry
     }
     my $seen_result = 0;
 
+    #if there was any output to stderr, mark this as a failure
+    foreach $line (@{$$tbl{stderr}})
+    {
+       printf "%-40s FAIL spurious stderr failure: %s\n", $test_name, $line;
+       $total_count++;
+       return;
+    }
+
     # scan all stdout looking for lines that start with PASS or FAIL
     foreach $line (@{$$tbl{stdout}})
     {
        if($line =~ m/^(PASS|XPASS|FAIL|XFAIL).+/)
        {
-           printf "%-40s %s\n", $test_name, $line;
            $total_count++;
            if($line =~ m/^PASS.+/)
            {
                $pass_count++;
            }
+           else
+           {
+               # only print failure lines
+               printf "%-40s %s\n", $test_name, $line;
+           }
            $seen_result = 1;
        }
     }
index 67c89c351ba8ac0307e8b5179fd9fbb860d6ba56..243fc2d0fc314ad2e7ecdd052b7986b77d9f16bc 100644 (file)
@@ -2,11 +2,17 @@
 
 SHELL = /bin/sh
 
-CC              = gcc-4.0 ${ARCH}
-CCFLAGS = -Wall -g -std=c99
+# set default to be host
+ARCH ?= $(shell arch)
 
-CXX              = g++-4.0 ${ARCH}
-CXXFLAGS = -Wall -g
+# set default to be all
+VALID_ARCHS ?= "ppc ppc64 i386 x86_64"
+
+CC              = gcc-4.0 -arch ${ARCH}
+CCFLAGS = -Wall -std=c99
+
+CXX              = g++-4.0 -arch ${ARCH}
+CXXFLAGS = -Wall 
 
 RM      = rm
 RMFLAGS = -rf
index ef857d18aef3046f5957ed9c51f811e0858f9243..0cfeb450b962c73f2080d0bc9ee0c0051a4d03f1 100755 (executable)
@@ -3,6 +3,10 @@
 # cd into test-cases directory
 cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 
+# save crash reporter state
+CRSTATE=`defaults read com.apple.CrashReporter DialogType`
+defaults write com.apple.CrashReporter DialogType basic
+
 echo ""
 echo " * * * Running all unit tests for 32-bits * * *"
 
@@ -22,11 +26,11 @@ then
        ../bin/make-recursive.pl clean > /dev/null
 
        # build 64-bit architecture
-       ../bin/make-recursive.pl ARCH="-arch ppc64" | ../bin/result-filter.pl
+       ../bin/make-recursive.pl ARCH="ppc64" | ../bin/result-filter.pl
 fi
 
 # if Intel, then also run all test cases under emulation
-if [ `sysctl -n hw.machine` = "i386" ] 
+if [ "`sysctl -n hw.machine`" = "i386" ] 
 then
        echo ""
        echo " * * * Running all unit tests for emulated 32-bits * * *"
@@ -35,18 +39,24 @@ then
        ../bin/make-recursive.pl clean > /dev/null
 
        # build ppc architecture
-       ../bin/make-recursive.pl ARCH="-arch ppc" | ../bin/result-filter.pl
-fi
+       ../bin/make-recursive.pl ARCH="ppc" | ../bin/result-filter.pl
 
-# if 64-bit capable Intel, then also run all test cases for 64-bits
-if [ `sysctl -n hw.optional.x86_64` = "1" ] 
-then
-       echo ""
-       echo " * * * Running all unit tests for 64-bits * * *"
-       
-       # make clean
-       ../bin/make-recursive.pl clean > /dev/null
 
-       # build x86_64 architecture
-       ../bin/make-recursive.pl ARCH="-arch x86_64" | ../bin/result-filter.pl
+       # if 64-bit capable Intel, then also run all test cases for 64-bits
+       if [ `sysctl -n hw.optional.x86_64` = "1" ] 
+       then
+               echo ""
+               echo " * * * Running all unit tests for 64-bits * * *"
+               
+               # make clean
+               ../bin/make-recursive.pl clean > /dev/null
+
+               # build x86_64 architecture
+               ../bin/make-recursive.pl ARCH="x86_64" | ../bin/result-filter.pl
+       fi
 fi
+
+# restore crash reporter state
+defaults write com.apple.CrashReporter DialogType ${CRSTATE}
+
+
index 3aeab86b0f4d6d0efe6b389abf93dd4734d27951..49c689a9488128d23c1d3ea42ce451f2699a355d 100644 (file)
@@ -29,13 +29,13 @@ run: all
 all: main
 
 main : main.c libbar.dylib libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main
+       ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main
 
 libfoo.dylib : foo.c libbar.dylib
        ${CC} -I${TESTROOT}/include -dynamiclib foo.c -o libfoo.dylib libbar.dylib
 
 libbar.dylib : bar.c
-       ${CC} -I${TESTROOT}/include -dynamiclib bar.c -o libbar.dylib -install_name /usr/local/hide/libbar.dylib
+       ${CC}  -I${TESTROOT}/include -dynamiclib bar.c -o libbar.dylib -install_name /usr/local/hide/libbar.dylib
 
 clean:
        ${RM} ${RMFLAGS} *~  main libbar.dylib libfoo.dylib
index e02d1403989aa0e1bd79f51dca8b7d9359b2e3a8..7d4b9f1832b172e1eb0d87d82449ecb3f3b60722 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main
 
 main : main.c
-       ${CC} -I${TESTROOT}/include main.c -o main
+       ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main
 
 clean:
        ${RM} ${RMFLAGS} *~  main
index 38794a055f994ce6cf43e3c94cb41d7d35b51f29..f46b18eff8931225cd6027717f9de512c86fc9ed 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main hide/libzzz.dylib
 
 main : main.c
-       ${CC} -I${TESTROOT}/include main.c -o main
+       ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main
 
 hide/libzzz.dylib:  zzz.c
        mkdir -p hide
diff --git a/unit-tests/test-cases/big-stack/Makefile b/unit-tests/test-cases/big-stack/Makefile
new file mode 100644 (file)
index 0000000..cc85b85
--- /dev/null
@@ -0,0 +1,33 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ${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
+
+clean:
+       ${RM} ${RMFLAGS} main
diff --git a/unit-tests/test-cases/big-stack/main.c b/unit-tests/test-cases/big-stack/main.c
new file mode 100644 (file)
index 0000000..dc1339a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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> // EXIT_SUCCESS
+#include <mach-o/dyld.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include "test.h"
+
+//
+// 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
+void foo(unsigned long long stackSize, char* stackStart) 
+{
+       char buffer[32*1024*1024];
+       keepAlive = buffer;
+       if ( (stackStart - buffer) > stackSize )
+               return;
+       else
+               foo(stackSize, stackStart);
+}
+
+#if __ppc__
+static bool isRosetta()
+{
+       int mib[] = { CTL_KERN, KERN_CLASSIC, getpid() };
+       int is_classic = 0;
+       size_t len = sizeof(int);
+       int ret = sysctl(mib, 3, &is_classic, &len, NULL, 0);
+       if ((ret != -1) && is_classic) {
+               // we're running under Rosetta 
+               return true;
+       }
+       return false;
+}
+#endif
+
+int
+main()
+{
+       char start;
+#if __ppc__
+       // programs running under rosetta cannot use large amounts of stack
+       if ( isRosetta() )
+               foo(0x02000000, &start);        
+       else
+#endif 
+               foo(0x81000000, &start);        // 2.1 GB stack
+       return EXIT_SUCCESS;
+}
+
+
index 2c905f269c2df812a9c6ebe415f2a0c8bb2ddca0..d2c407c28dccf919861a055a32ffaf7049b58b01 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
diff --git a/unit-tests/test-cases/bundle-dont-gc/Makefile b/unit-tests/test-cases/bundle-dont-gc/Makefile
new file mode 100644 (file)
index 0000000..6728b7a
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main
+
+main: main.c foo.bundle bar.bundle
+       ${CC} ${CCFLAGS}  -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c 
+
+foo.bundle : foo.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle  foo.c 
+       
+bar.bundle : bar.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o bar.bundle  bar.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle bar.bundle
+
diff --git a/unit-tests/test-cases/bundle-dont-gc/bar.c b/unit-tests/test-cases/bundle-dont-gc/bar.c
new file mode 100644 (file)
index 0000000..3aee7ab
--- /dev/null
@@ -0,0 +1,3 @@
+
+void bar() {}
+
diff --git a/unit-tests/test-cases/bundle-dont-gc/foo.c b/unit-tests/test-cases/bundle-dont-gc/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/bundle-dont-gc/main.c b/unit-tests/test-cases/bundle-dont-gc/main.c
new file mode 100644 (file)
index 0000000..69e2f2c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 <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[])
+{
+       // load foo.bundle with old API
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromFile("foo.bundle", &ofi) != NSObjectFileImageSuccess ) {
+               FAIL("bundle-dont-gc: NSCreateObjectFileImageFromFile failed");
+               return 1;
+       }
+       
+       NSModule mod = NSLinkModule(ofi, "foo.bundle", NSLINKMODULE_OPTION_NONE);
+       if ( mod == NULL ) {
+               FAIL("bundle-dont-gc: NSLinkModule failed");
+               return 1;
+       }
+       
+       NSSymbol sym = NSLookupSymbolInModule(mod, "_foo");
+       if ( sym == NULL ) {
+               FAIL("bundle-dont-gc: NSLookupSymbolInModule failed");
+               return 1;
+       }
+
+       void* fooAddr = NSAddressOfSymbol(sym);
+       if ( fooAddr == NULL ) {
+               FAIL("bundle-dont-gc: NSAddressOfSymbol failed");
+               return 1;
+       }
+
+       if ( !NSDestroyObjectFileImage(ofi) ) {
+               FAIL("bundle-dont-gc: NSDestroyObjectFileImage failed");
+               return 1;
+       }
+
+       // open and close bar.bundle with new API, which causes a gc of images
+       void* h1 = dlopen("bar.bundle", RTLD_LAZY);
+       if ( h1 == NULL ) {
+               FAIL("bundle-dont-gc: can't dlopen bar.bundle: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       dlclose(h1);
+       
+       // make sure foo is still loaded
+       Dl_info info;
+       if ( dladdr(fooAddr, &info) == 0 ) {
+               FAIL("bundle-dont-gc: dladdr() failed");
+               exit(0);
+       }
+       
+       // unload foo.bundle with old API
+       if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) {
+               FAIL("NSUnLinkModule failed");
+               return 1;
+       }
+               
+       
+       PASS("bundle-dont-gc");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/bundle-memory-load-bad/Makefile b/unit-tests/test-cases/bundle-memory-load-bad/Makefile
new file mode 100644 (file)
index 0000000..4b3865d
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# 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@
+##
+
+
+#
+# The test case verifies that dyld can cleanly recover from
+# a main executable (test.bundle) being used with 
+# NSCreateObjectFileImageFromMemory()
+#
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./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} -o test.bundle bundle.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main test.bundle
+
diff --git a/unit-tests/test-cases/bundle-memory-load-bad/bundle.c b/unit-tests/test-cases/bundle-memory-load-bad/bundle.c
new file mode 100644 (file)
index 0000000..7556138
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int main()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/bundle-memory-load-bad/main.c b/unit-tests/test-cases/bundle-memory-load-bad/main.c
new file mode 100644 (file)
index 0000000..fe100da
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <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 "test.h" // PASS(), FAIL()
+
+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 = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( loadAddress == ((void*)(-1)) ) {
+               FAIL("mmap() failed");
+               return 1;
+       }
+
+       close(fd);
+
+       // we are using a file not of type MH_BUNDLE, so NSCreateObjectFileImageFromMemory should fail
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) 
+               PASS("bundle-memory-load-bad");
+       else
+               FAIL("bundle-memory-load-bad");
+       
+       return 0;
+}
\ No newline at end of file
index 01eab8b6b6953d530ff36f07a46d396abb093be9..7c573149cfa0389872392ef9131227e14cb54722 100644 (file)
@@ -31,10 +31,10 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS}  -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
 
 test.bundle : bundle.c
-       ${CC} ${FATFLAGS} -bundle -o test.bundle bundle.c
+       gcc ${FATFLAGS} -bundle -o test.bundle bundle.c
 
 clean:
        ${RM} ${RMFLAGS} *~ main test.bundle
index 2c905f269c2df812a9c6ebe415f2a0c8bb2ddca0..a44aecad6f09d29aa2e0470a295c6561b0ce99b5 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
index ce5b2d482ca764c64175dad7e1d7b7424c424d30..c044f7f0bebba115492e1ca00a2bfa0f56641def 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
index 267d540e180d094c4a986d37bc145bcb43d3f098..10d9fce9b737f466dda7693aa797f502ca50466b 100644 (file)
@@ -62,7 +62,9 @@ int main()
 
        NSModule mod2 = NSLinkModule(ofi, "test2.bundle", NSLINKMODULE_OPTION_NONE);
        if ( mod2 == NULL ) {
-               FAIL("2nd NSLookupSymbolInModule failed");
+               NSLinkEditErrors c; int errorNumber; const char* fileName; const char* errorString;
+               NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
+               FAIL("2nd NSLinkModule failed: %s", errorString);
                return 0;
        }
        if ( mod == mod2 ) {
@@ -150,9 +152,9 @@ int main()
        }
 
        // check that this is really a new copy by verifying the getValue() returns zero
-       NSSymbol sym4getter = NSLookupSymbolInModule(mod2, "_getValue");
+       NSSymbol sym4getter = NSLookupSymbolInModule(mod4, "_getValue");
        if ( sym4getter == NULL ) {
-               FAIL("2nd NSLookupSymbolInModule failed");
+               FAIL("4th NSLookupSymbolInModule failed");
                return 0;
        }
        getter func4getter = NSAddressOfSymbol(sym4getter);
index ce5b2d482ca764c64175dad7e1d7b7424c424d30..c044f7f0bebba115492e1ca00a2bfa0f56641def 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
index 5d4d052156f8ba8c3bcf3b7fb9c9e2df45423646..b9eb8b3867426051b4eb8b6ae832b57315b15af9 100644 (file)
@@ -51,7 +51,7 @@ int main()
        }
 
        void* func = NSAddressOfSymbol(sym);
-       fprintf(stderr, "1st address of foo() = %p in module %p in OFI %p\n", func, mod, ofi);
+       //fprintf(stderr, "1st address of foo() = %p in module %p in OFI %p\n", func, mod, ofi);
 
 
        NSObjectFileImage ofi2;
@@ -77,7 +77,7 @@ int main()
        }
 
        void* func2 = NSAddressOfSymbol(sym2);
-       fprintf(stderr, "2nd address of foo() = %p in module %p in OFI %p\n", func2, mod2, ofi2);
+       //fprintf(stderr, "2nd address of foo() = %p in module %p in OFI %p\n", func2, mod2, ofi2);
        if ( func == func2 ) {
                FAIL("2nd NSAddressOfSymbol return same function address as 1st\n");
                return 0;
@@ -109,7 +109,7 @@ int main()
                return 0;
        }
        void* func3 = NSAddressOfSymbol(sym3);
-       fprintf(stderr, "3rd address of foo() = %p in module %p in OFI %p\n", func3, mod3, ofi3);
+       //fprintf(stderr, "3rd address of foo() = %p in module %p in OFI %p\n", func3, mod3, ofi3);
        if ( func3 == func ) {
                FAIL("3rd NSAddressOfSymbol return same function address as 1st\n");
                return 0;
diff --git a/unit-tests/test-cases/bundle-name-ownership/Makefile b/unit-tests/test-cases/bundle-name-ownership/Makefile
new file mode 100644 (file)
index 0000000..f2d2d0a
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./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-name-ownership/bundle.c b/unit-tests/test-cases/bundle-name-ownership/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-name-ownership/main.c b/unit-tests/test-cases/bundle-name-ownership/main.c
new file mode 100644 (file)
index 0000000..4244489
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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>
+#include <dlfcn.h> 
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL()
+
+typedef bool (*CheckFunc)();
+
+int main()
+{
+       const char* path = "test.bundle";
+
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromFile(path, &ofi) != NSObjectFileImageSuccess ) {
+               FAIL("NSCreateObjectFileImageFromFile failed");
+               return 0;
+       }
+       
+       NSModule mod = NSLinkModule(ofi, path, NSLINKMODULE_OPTION_NONE);
+       if ( mod == NULL ) {
+               FAIL("NSLinkModule failed");
+               return 0;
+       }
+       
+       NSSymbol sym = NSLookupSymbolInModule(mod, "_checkdata");
+       if ( sym == NULL ) {
+               FAIL("NSLookupSymbolInModule failed");
+               return 0;
+       }
+
+       CheckFunc func = NSAddressOfSymbol(sym);
+       if ( !func() ) {
+               FAIL("NSAddressOfSymbol failed");
+               return 0;
+       }
+
+       Dl_info info;
+       if ( dladdr(func, &info) == 0 ) {
+               FAIL("dladdr(func, &info) failed");
+               return 0;
+       }
+       
+       if ( info.dli_fname == path ) {
+               FAIL("NSLinkModule() did not make a copy of the path");
+               return 0;
+       }
+
+       if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) {
+               FAIL("NSUnLinkModule failed");
+               return 0;
+       }
+
+       if ( !NSDestroyObjectFileImage(ofi) ) {
+               FAIL("NSDestroyObjectFileImage failed");
+               return 0;
+       }
+
+       PASS("bundle-name-ownership");
+       return 0;
+}
\ No newline at end of file
index 2c905f269c2df812a9c6ebe415f2a0c8bb2ddca0..29d5d415e459ed5600d5bd141a139151a784036f 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
index 194c744a2e9e88ad28a792347fdff9b5c181db65..97eb0d5ca5b05c1dfd11eb4bfc0df779bc11ca18 100644 (file)
@@ -23,7 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-ifeq "-arch ppc" "$(ARCH)"
+ifeq "ppc" "$(ARCH)"
        CXX_VERSION = g++-3.3 
 else 
        CXX_VERSION = ${CXX} 
@@ -35,7 +35,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
 
 test.bundle : bundle.cxx
        ${CXX} ${CXXFLAGS} -bundle -o test.bundle bundle.cxx
index ec27354463fce96be55df918a423a82e22774286..a8651c4b8ea2e79d8e2414b5f5a48aaa8bde9fab 100644 (file)
@@ -27,3 +27,4 @@ void foo()
 {
 }
 
+int __attribute__((weak)) blah = 10;
index e7f9fd2228895e23f687ad530b241cd9555de573..bb9c30d350cf5ac5d748f054ae0e650c1f5c9979 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c
 
 test.bundle : bundle.c libstuff.dylib
        ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c libstuff.dylib
index 2c905f269c2df812a9c6ebe415f2a0c8bb2ddca0..f2d2d0a7a8358a467f3d8c4d2454cd980a549cdc 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o 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
index e2df5ede44c07dbd1db8d3de7410751c725cd2f1..952c3a5b3963fb66076db76ecdabbc0e9aa04346 100644 (file)
@@ -28,8 +28,8 @@ run: all
 
 all: main 
 
-main : main.c bar.dylib foo.bundle foo.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c bar.dylib
+main : main.c bar.dylib foo.bundle foo.dylib foo2.dylib
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c bar.dylib
 
 foo.bundle : foo.c
        ${CC} ${CCFLAGS} -bundle -o foo.bundle foo.c
@@ -37,9 +37,12 @@ foo.bundle : foo.c
 foo.dylib : foo.c
        ${CC} ${CCFLAGS} -dynamiclib -o foo.dylib foo.c
 
+foo2.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib -o foo2.dylib foo.c
+
 bar.dylib : bar.c
        ${CC} ${CCFLAGS} -dynamiclib -o bar.dylib bar.c
 
 clean:
-       ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib bar.dylib
+       ${RM} ${RMFLAGS} *~ main foo.bundle foo.dylib foo2.dylib bar.dylib
 
index 4f0e3a90f2efd19ea84165b066f59a21cb7d7e5b..8caba38d6269e2f5ce70a09d6f90e0ff631f0da7 100644 (file)
 #include <stdbool.h>
 #include <stdlib.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 "test.h" // PASS(), FAIL()
 
 
+void loadAsBundleFromMemory(const char* path)
+{
+       int fd = open(path, O_RDONLY, 0);
+       if ( fd == -1 ) {
+               FAIL("bundle-v-dylib: open() failed");
+               exit(0);
+       }
+
+       struct stat stat_buf;
+       if ( fstat(fd, &stat_buf) == -1) {
+               FAIL("bundle-v-dylib: fstat() failed");
+               exit(0);
+       }
+
+       void* loadAddress = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( loadAddress == ((void*)(-1)) ) {
+               FAIL("bundle-v-dylib: mmap() failed");
+               exit(0);
+       }
+
+       close(fd);
+
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) == NSObjectFileImageSuccess ) {
+               FAIL("bundle-v-dylib: NSCreateObjectFileImageFromMemory() incorrectly allowed %s to be loaded", path);
+               exit(0);
+       }
+}
+
 void loadAsBundle(const char* path)
 {
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile(path, &ofi) == NSObjectFileImageSuccess ) {
-               FAIL("NSCreateObjectFileImageFromFile() incorrectly allowed %s to be loaded", path);
-               exit(1);
+               FAIL("bundle-v-dylib: NSCreateObjectFileImageFromFile() incorrectly allowed %s to be loaded", path);
+               exit(0);
        }
 }
 
 void loadAsDylib(const char* path)
 {
        if ( NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR) != NULL ) {
-               FAIL("NSAddImage() incorrectly allowed %s to be loaded", path);
-               exit(1);
+               FAIL("bundle-v-dylib: NSAddImage() incorrectly allowed %s to be loaded", path);
+               exit(0);
        }
 }
 
-
 extern void bar();
 
 int main()
 {
+       int dummy; 
+       
        // verify that NSAddImage fails to load MH_BUNDLE
        loadAsDylib("foo.bundle");
 
@@ -58,9 +93,16 @@ int main()
 
        // verify that NSCreateObjectFileImageFromFile fails to load MH_DYLIB already linked against main
        loadAsBundle("bar.dylib");
+       
        // verify that bar.dylib was not unloaded when above failed
        bar();
        
+       // try loading a dylib from memory using bundle API's
+       loadAsBundleFromMemory("foo2.dylib");
+       
+       // verify that dyld data structures are not wanked by scanning all images
+       _dyld_get_image_header_containing_address(&dummy);
+
        PASS("bundle-v-dylib");
        return 0;
 }
\ No newline at end of file
diff --git a/unit-tests/test-cases/bundle-weak/Makefile b/unit-tests/test-cases/bundle-weak/Makefile
new file mode 100644 (file)
index 0000000..3cf265b
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main test.bundle
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+test.bundle : bundle.cxx
+       ${CXX} ${CCXXFLAGS} -bundle -o test.bundle bundle.cxx
+
+clean:
+       ${RM} ${RMFLAGS} *~ main test.bundle
+
diff --git a/unit-tests/test-cases/bundle-weak/bundle.cxx b/unit-tests/test-cases/bundle-weak/bundle.cxx
new file mode 100644 (file)
index 0000000..fb36871
--- /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@
+ */
+#include <vector>
+#include <stdexcept>
+#include <cassert>
+#include <stdio.h>
+
+bool test()
+{
+       try { 
+               std::vector<int>().at(1); 
+       }
+       catch(const std::out_of_range&) { 
+               //fprintf(stderr, "caught out_of_range\n");
+               return true;
+       }
+       catch(...) {
+               //fprintf(stderr, "caught something\n");
+       }
+       return false;
+}
diff --git a/unit-tests/test-cases/bundle-weak/main.c b/unit-tests/test-cases/bundle-weak/main.c
new file mode 100644 (file)
index 0000000..2de9a58
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL()
+
+typedef bool (*CheckFunc)();
+
+int main()
+{
+       void* handle = dlopen("test.bundle", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\test.bundle\") failed");
+               return 0;
+       }
+       
+       CheckFunc func = (CheckFunc)dlsym(handle, "_Z4testv");
+       if ( func == NULL ) {
+               FAIL("dlsym(handle, \"__Z4testv\") failed");
+               return 0;
+       }
+       
+       if ( func() )
+               PASS("bundle-weak");
+       else
+               FAIL("bundle-weak");
+               
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/crt-apple/Makefile b/unit-tests/test-cases/crt-apple/Makefile
new file mode 100644 (file)
index 0000000..0905421
--- /dev/null
@@ -0,0 +1,57 @@
+##
+# 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 that apple[0] parameter is correct by comparing to argv[1]
+#
+
+run: all
+       ./main-10.4 ./main-10.4
+       ./main-10.5 ./main-10.5
+       ./main-10.4.stripped ./main-10.4.stripped
+       ./main-10.5.stripped ./main-10.5.stripped
+       `pwd`/main-10.4 `pwd`/main-10.4
+       `pwd`/main-10.5 `pwd`/main-10.5
+       `pwd`/main-10.4.stripped `pwd`/main-10.4.stripped
+       `pwd`/main-10.5.stripped `pwd`/main-10.5.stripped
+
+all: main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+
+main-10.4: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4 -w
+
+main-10.4.stripped: main-10.4
+       strip main-10.4 -o main-10.4.stripped
+       
+main-10.5: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5 -w
+
+main-10.5.stripped: main-10.5
+       strip main-10.5 -o main-10.5.stripped
+
+clean:
+       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+
diff --git a/unit-tests/test-cases/crt-apple/main.c b/unit-tests/test-cases/crt-apple/main.c
new file mode 100644 (file)
index 0000000..05959bb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 <stdbool.h>
+#include <string.h>
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// verify that apple[0] parameter is correct by comparing to argv[1]
+///
+
+int
+main(int argc, const char* argv[], const char* env[], const char* apple[])
+{
+       if ( strcmp(apple[0], argv[1]) == 0 )
+               PASS("crt-apple %s", argv[0]);
+       else
+               FAIL("crt-apple %s", argv[0]);
+               
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/crt-argv-NULL/Makefile b/unit-tests/test-cases/crt-argv-NULL/Makefile
new file mode 100644 (file)
index 0000000..9df7f9b
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# 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
+
+#
+# verifies that crt glue can handle  argv[0] = NULL
+#
+
+run: all
+       ${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
+
+
+all:  main-10.4  main-10.5
+
+main-10.4: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4
+
+main-10.5: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5
+
+clean:
+       ${RM} ${RMFLAGS} *~ main-10.4  main-10.5
+
diff --git a/unit-tests/test-cases/crt-argv-NULL/main.c b/unit-tests/test-cases/crt-argv-NULL/main.c
new file mode 100644 (file)
index 0000000..1adc975
--- /dev/null
@@ -0,0 +1,14 @@
+
+ #include <unistd.h>
+int main(int argc, const char* argv[]) 
+{ 
+       if ( argv[0] != NULL ) {
+               // re-exec with empty argv[] array
+               char* const emptyArgv[] = { NULL };
+               execv(argv[0], emptyArgv);
+       }
+
+       return 0; 
+}
diff --git a/unit-tests/test-cases/crt-custom/Makefile b/unit-tests/test-cases/crt-custom/Makefile
new file mode 100644 (file)
index 0000000..d07ac32
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verifies that 10.4 binaries with a custom entry point
+# have the entry point called before initializers are run
+#
+
+run: all
+       ./main-10.4
+       ./main-10.5
+
+
+all: main-10.4 main-10.5
+
+main-10.4: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 mystart.s main.c -mmacosx-version-min=10.4 -e _mystart
+
+main-10.5: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 mystart.s main.c -mmacosx-version-min=10.5 -e _mystart
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5
+
diff --git a/unit-tests/test-cases/crt-custom/main.c b/unit-tests/test-cases/crt-custom/main.c
new file mode 100644 (file)
index 0000000..0986fd0
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// the value of flag is altered by mystart
+int flag = 0;
+
+
+#if __LP64__
+       // for 64-bit binaries initializers are always called before entry point
+       #define ENTRY_BEFORE_INIT 0
+#else
+       // for pre 10.5, 32-bit binaries, entry point is called which then calls initializers
+       #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+               #define ENTRY_BEFORE_INIT 1
+       #else
+               #define ENTRY_BEFORE_INIT 0
+       #endif
+#endif
+
+
+void __attribute__((constructor)) myinit()
+{
+#if ENTRY_BEFORE_INIT
+       if ( flag != 2 ) {
+               FAIL("crt-custom entry point not called before initializer");
+               exit(0);
+       }
+#endif
+       flag = 1;
+}
+
+
+int main() 
+{ 
+#if ENTRY_BEFORE_INIT
+       if ( flag != 1 ) {
+               FAIL("crt-custom initializer not called");
+               exit(0);
+       }
+#else
+       if ( flag != 2 ) {
+               FAIL("crt-custom entry not called");
+               exit(0);
+       }
+#endif
+
+       PASS("crt-custom");
+
+       return 0; 
+}
diff --git a/unit-tests/test-cases/crt-custom/mystart.s b/unit-tests/test-cases/crt-custom/mystart.s
new file mode 100644 (file)
index 0000000..b4cb9be
--- /dev/null
@@ -0,0 +1,20 @@
+
+
+
+       .text
+       .globl _mystart
+_mystart:
+#if __i386__ 
+       movl    $2, _flag
+       jmp             start
+#elif __x86_64__
+       movl    $2, _flag(%rip)
+       jmp             start
+#elif __ppc__ || __ppc64__
+       li r0,2
+       lis r2,ha16(_flag)
+       stw r0,lo16(_flag)(r2)
+       b               start
+#endif
+
+
diff --git a/unit-tests/test-cases/crt-libSystem/Makefile b/unit-tests/test-cases/crt-libSystem/Makefile
new file mode 100644 (file)
index 0000000..8d8b832
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# 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
+
+#
+# verifies that _NS* routines in libSystem properly find global variables in main executable.
+# the mechanism for 10.4 and 10.5 is different 
+#
+
+run: all
+       ./main-10.4
+       ./main-10.5
+       ./main-10.4.stripped
+       ./main-10.5.stripped
+
+all: main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+
+main-10.4: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4
+
+main-10.4.stripped: main-10.4
+       strip main-10.4 -o main-10.4.stripped
+       
+main-10.5: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5
+
+main-10.5.stripped: main-10.5
+       strip main-10.5 -o main-10.5.stripped
+
+clean:
+       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+
diff --git a/unit-tests/test-cases/crt-libSystem/main.c b/unit-tests/test-cases/crt-libSystem/main.c
new file mode 100644 (file)
index 0000000..b7027df
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <crt_externs.h>
+#include <mach-o/ldsyms.h>
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+struct ProgramVars
+{
+       const void*             mh;
+       int*                    NXArgcPtr;
+       char***                 NXArgvPtr;
+       char***                 environPtr;
+       char**                  __prognamePtr;
+};
+static const struct ProgramVars* sVars;
+
+// global variables defeined in crt1.o
+extern char** NXArgv;
+extern int NXArgc;
+extern char** environ;
+extern char* __progname;
+
+
+int
+main(int argc, const char* argv[])
+{
+       bool success = true;
+
+       if ( _NSGetArgv() != &NXArgv ) {
+               FAIL("crt-libSystem _NSGetArgv() != &NXArgv (%p!=%p) for %s", _NSGetArgv(), &NXArgv, argv[0]);
+               success = false;
+       }
+       
+       if ( _NSGetArgc() != &NXArgc ) {
+               FAIL("crt-libSystem _NSGetArgc() != &NXArgc (%p!=%p) for %s", _NSGetArgc(), &NXArgc, argv[0]);
+               success = false;
+       }
+       
+       if ( _NSGetEnviron() != &environ ) {
+               FAIL("crt-libSystem _NSGetEnviron() != &environv (%p!=%p) for %s", _NSGetEnviron(), &environ, argv[0]);
+               success = false;
+       }
+       
+       if ( _NSGetProgname() != &__progname ) {
+               FAIL("crt-libSystem _NSGetProgname() != &__progname (%p!=%p) for %s", _NSGetProgname(), &__progname, argv[0]);
+               success = false;
+       }
+       
+       if ( _NSGetMachExecuteHeader() != &_mh_execute_header ) {
+               FAIL("crt-libSystem _NSGetMachExecuteHeader() != &_mh_execute_headerv (%p!=%p) for %s", _NSGetMachExecuteHeader(), &_mh_execute_header, argv[0]);
+               success = false;
+       }
+       
+       if ( sVars->NXArgvPtr != &NXArgv ) {
+               FAIL("crt-libSystem sVars->NXArgvPtr != &NXArg (%p!=%p) for %s", sVars->NXArgvPtr, &NXArgv, argv[0]);
+               success = false;
+       }
+
+       if ( sVars->NXArgcPtr != &NXArgc ) {
+               FAIL("crt-libSystem sVars->NXArgcPtr != &NXArgc (%p!=%p) for %s", sVars->NXArgcPtr, &NXArgc, argv[0]);
+               success = false;
+       }
+       
+       if ( sVars->environPtr != &environ ) {
+               FAIL("crt-libSystem sVars->environPtr != &environ (%p!=%p) for %s", sVars->environPtr, &environ, argv[0]);
+               success = false;
+       }
+       
+       if ( sVars->__prognamePtr != &__progname ) {
+               FAIL("crt-libSystem sVars->__prognamePtr != &__progname (%p!=%p) for %s", sVars->__prognamePtr, &__progname, argv[0]);
+               success = false;
+       }
+       
+       if ( sVars->mh != &_mh_execute_header ) {
+               FAIL("crt-libSystem sVars->mh != &_mh_execute_header (%p!=%p) for %s", sVars->mh, &_mh_execute_header, argv[0]);
+               success = false;
+       }
+       
+       if ( success )
+               PASS("crt-libSystem");
+               
+       return EXIT_SUCCESS;
+}
+
+
+
+void __attribute__((constructor))
+myInit(int argc, const char* argv[], const char* envp[], const char* apple[], const struct ProgramVars* vars)
+{
+       sVars = vars;
+}
+
+
+
+
+
diff --git a/unit-tests/test-cases/crt-result/Makefile b/unit-tests/test-cases/crt-result/Makefile
new file mode 100644 (file)
index 0000000..8e7cbf3
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# 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
+
+#
+# verifies that the return value from main() makes it to shell
+# for both crt1.0 and crt1.10.5.o
+#
+
+run: all
+       ${TESTROOT}/bin/exit-zero-pass.pl "crt-result good-10.4" "crt-result good-10.4"    ./good-10.4
+       ${TESTROOT}/bin/exit-zero-pass.pl "crt-result good-10.5" "crt-result good-10.5"    ./good-10.5
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "crt-result bad-10.4" "crt-result bad-10.4"  ./bad-10.4
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "crt-result bad-10.5" "crt-result bad-10.5"  ./bad-10.5
+
+
+all: good-10.4 good-10.5  bad-10.4 bad-10.5 
+
+good-10.4: good.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o good-10.4 good.c -mmacosx-version-min=10.4
+
+good-10.5: good.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o good-10.5 good.c -mmacosx-version-min=10.5
+
+bad-10.4: bad.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o bad-10.4 bad.c -mmacosx-version-min=10.4
+
+bad-10.5: bad.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o bad-10.5 bad.c -mmacosx-version-min=10.5
+
+clean:
+       ${RM} ${RMFLAGS} *~ good-10.4 good-10.5  bad-10.4 bad-10.5 
+
diff --git a/unit-tests/test-cases/crt-result/bad.c b/unit-tests/test-cases/crt-result/bad.c
new file mode 100644 (file)
index 0000000..40cbb54
--- /dev/null
@@ -0,0 +1 @@
+int main() { return 1; }
diff --git a/unit-tests/test-cases/crt-result/good.c b/unit-tests/test-cases/crt-result/good.c
new file mode 100644 (file)
index 0000000..76e8197
--- /dev/null
@@ -0,0 +1 @@
+int main() { return 0; }
index 76d4808000094e81665ccb950245213494fe1dd8..c21045d23d5f99cd7923c439fa59507ce052eaab 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main 
 
 main : main.c bar.dylib foo.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.dylib
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c foo.dylib
 
 foo.dylib : foo.c
        ${CC} ${CCFLAGS} -dynamiclib -o foo.dylib foo.c
index 07ad467803bfd9f82ce0cbc9b690008235c4607c..9727ccb66ef05e205c7d8bf63bf6e6c37d23e32e 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <pthread.h>
+#include <unistd.h>
 
 #include "test.h"
 
index b0ee016fa5c95e8031d02efed404d9f40a98f53b..fcb934dbda1536b39cc7298a9fb2b9dcd6badb07 100644 (file)
@@ -27,7 +27,7 @@ run: all
        ./main
 
 all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c
 
 clean:
        ${RM} ${RMFLAGS} *~ main
diff --git a/unit-tests/test-cases/dlclose-dylib-unload/Makefile b/unit-tests/test-cases/dlclose-dylib-unload/Makefile
new file mode 100644 (file)
index 0000000..2597b53
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main libfoo.dylib 
+
+main : main.c libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libbar.dylib -o main 
+
+
+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/dlclose-dylib-unload/bar.c b/unit-tests/test-cases/dlclose-dylib-unload/bar.c
new file mode 100644 (file)
index 0000000..817b8cd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int bar()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-unload/foo.c b/unit-tests/test-cases/dlclose-dylib-unload/foo.c
new file mode 100644 (file)
index 0000000..81f7dcf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-unload/main.c b/unit-tests/test-cases/dlclose-dylib-unload/main.c
new file mode 100644 (file)
index 0000000..5e48c00
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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()
+
+
+
+
+
+void verifyfoo()
+{
+       // open same dylib three times
+       void* handle1 = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle1 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+       
+       void* handle2 = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle2 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+
+       void* handle3 = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle3 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+
+       // get symbol
+       void* sym = dlsym(handle1, "foo");
+       if ( sym == NULL ) {
+               FAIL("dlclose-dylib-unload: dlsym(handle1, \"foo\") failed");
+               exit(0);
+       }
+
+       // close same bundle three times
+       if ( dlclose(handle3) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle3) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       if ( dlclose(handle2) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle2) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       if ( dlclose(handle1) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle1) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       // symbol foo should no longer be accessible via dladdr()
+       Dl_info info;
+       if ( dladdr(sym, &info) != 0 ) {
+               FAIL("dlclose-dylib-unload: dladdr(foo_sym) != 0, but should have failed");
+               //exit(0);
+       }
+
+       // extra close should fail
+       if ( dlclose(handle1) == 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(foo_handle4) == 0, but should have failed");
+               //exit(0);
+       }
+       
+}
+
+
+
+void verifybar()
+{
+       // open same dylib three times
+       void* handle1 = dlopen("libbar.dylib", RTLD_LAZY);
+       if ( handle1 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libbar.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+       
+       void* handle2 = dlopen("libbar.dylib", RTLD_LAZY);
+       if ( handle2 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libbar.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+
+       void* handle3 = dlopen("libbar.dylib", RTLD_LAZY);
+       if ( handle3 == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libbar.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+
+       // get symbol
+       void* sym = dlsym(handle1, "bar");
+       if ( sym == NULL ) {
+               FAIL("dlclose-dylib-unload: dlsym(handle1, \"bar\") failed");
+               exit(0);
+       }
+
+       // close same bundle three times
+       if ( dlclose(handle3) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle3) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       if ( dlclose(handle2) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle2) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       if ( dlclose(handle1) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle1) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+
+       // symbol bar should still longer be accessible via dladdr() because of external reference to libbar.dylib
+       Dl_info info;
+       if ( dladdr(sym, &info) == 0 ) {
+               FAIL("dlclose-dylib-unload: dladdr(bar_sym) == 0, but should have succeeded");
+               exit(0);
+       }
+
+       // extra close should fail
+       if ( dlclose(handle1) == 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(bar_handle4) == 0, but should have failed");
+               exit(0);
+       }
+}
+
+
+// verify libbar.dylib can be loaded and unloaded
+// verify libbar.dylib can be loaded, but cannot be unloaded (because main executable links against it)
+int main()
+{
+       verifyfoo();
+       verifybar();
+       
+       PASS("dlclose-dylib-unload");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlclose-terminator-dlclose/Makefile b/unit-tests/test-cases/dlclose-terminator-dlclose/Makefile
new file mode 100644 (file)
index 0000000..4f19e3f
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+# <rdar://problem/5366233> Leopard (9a499): dyld crash with recursive calls to dlclose()
+
+
+run: all
+       ./main
+
+all: main libfoo.dylib 
+
+main : main.c libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libbar.dylib -o main 
+
+
+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/dlclose-terminator-dlclose/bar.c b/unit-tests/test-cases/dlclose-terminator-dlclose/bar.c
new file mode 100644 (file)
index 0000000..6cd208d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int bar()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-terminator-dlclose/foo.c b/unit-tests/test-cases/dlclose-terminator-dlclose/foo.c
new file mode 100644 (file)
index 0000000..e12dc61
--- /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 <stddef.h>
+#include <dlfcn.h>
+
+
+// <rdar://problem/5366233> Leopard (9a499): dyld crash with recursive calls to dlclose()
+
+static void* handle = NULL;
+
+static void __attribute__((constructor)) myinit()
+{
+       handle = dlopen("libbar.dylib", RTLD_LAZY);
+}
+
+static void __attribute__((destructor)) myterm()
+{
+       // myterm() is called within dlclose.
+       // now call dlclose() on another (chainded dylib) to test dlclose is re-entrant
+       if ( handle != NULL )
+               dlclose(handle);
+}
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-terminator-dlclose/main.c b/unit-tests/test-cases/dlclose-terminator-dlclose/main.c
new file mode 100644 (file)
index 0000000..90ea779
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlclose-dylib-unload: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+       
+
+       if ( dlclose(handle) != 0 ) {
+               FAIL("dlclose-dylib-unload: dlclose(handle) != 0, dlerrr()=%s", dlerror());
+               exit(0);
+       }
+       
+       PASS("dlclose-terminator-dlclose");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlclose-unload-c++/Makefile b/unit-tests/test-cases/dlclose-unload-c++/Makefile
new file mode 100644 (file)
index 0000000..8cce77e
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main libfoo.dylib libbar.dylib
+
+main : main.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+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/dlclose-unload-c++/bar.c b/unit-tests/test-cases/dlclose-unload-c++/bar.c
new file mode 100644 (file)
index 0000000..c69ec99
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+static void local()
+{
+}
+
+extern void* common() __attribute__((weak));
+
+void* common() 
+{
+       return &local;
+}
+
+void* bar()
+{
+       return common();
+}
diff --git a/unit-tests/test-cases/dlclose-unload-c++/foo.c b/unit-tests/test-cases/dlclose-unload-c++/foo.c
new file mode 100644 (file)
index 0000000..b6bd1e4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+static void local()
+{
+}
+
+extern void* common() __attribute__((weak));
+
+void* common() 
+{
+       return &local;
+}
+
+void* foo()
+{
+       return common();
+}
diff --git a/unit-tests/test-cases/dlclose-unload-c++/main.c b/unit-tests/test-cases/dlclose-unload-c++/main.c
new file mode 100644 (file)
index 0000000..cada146
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 <stdbool.h>
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+///
+/// This tests that if a C++ symbol (any weak symbol) is bound to an image
+/// that is dynamically unloaed, the image is not unloaded until all its clients are
+///
+
+typedef void* (*proc)(void);
+
+bool inImage(void* x)
+{
+  Dl_info info;
+  return ( dladdr(x, &info) != 0 );
+}
+
+
+int main()
+{
+       void* handle1 = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle1 == NULL ) {
+               FAIL("dlclose-unload-c++: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+       
+       proc fooProc = (proc)dlsym(handle1, "foo");
+       if ( fooProc == NULL ) {
+               FAIL("dlclose-unload-c++: dlsym(handle1, \"foo\") failed");
+               exit(0);
+       }
+
+       void* handle2 = dlopen("libbar.dylib", RTLD_LAZY);
+       if ( handle2 == NULL ) {
+               FAIL("dlclose-unload-c++: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+               exit(0);
+       }
+
+       proc barProc = (proc)dlsym(handle2, "bar");
+       if ( barProc == NULL ) {
+               FAIL("dlclose-unload-c++: dlsym(handle2, \"bar\") failed");
+               exit(0);
+       }
+
+       // verify that uniquing is happening
+       void* fooResult = (*fooProc)();
+       void* barResult = (*barProc)();
+       if ( fooResult != barResult ) {
+               FAIL("dlclose-unload-c++: foo() and bar() returned different values");
+               exit(0);
+       }
+       
+       // close libfoo, even though libbar is using libfoo
+       dlclose(handle1);
+       
+       // error if libfoo was unloaded
+       if ( !inImage(fooProc) ) {
+               FAIL("dlclose-unload-c++: libfoo should not have been unloaded");
+               exit(0);
+       }
+       
+       // close libbar which should release libfoo
+       dlclose(handle2);
+       
+       // error if libfoo was not unloaded
+       if ( inImage(fooProc) ) {
+               FAIL("dlclose-unload-c++: libfoo should have been unloaded");
+               exit(0);
+       }
+               
+       PASS("dlclose-unload-c++");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlerror-clear/Makefile b/unit-tests/test-cases/dlerror-clear/Makefile
new file mode 100644 (file)
index 0000000..7337131
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main 
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/dlerror-clear/main.c b/unit-tests/test-cases/dlerror-clear/main.c
new file mode 100644 (file)
index 0000000..f70cc86
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 <string.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// This tests that the dlerror message is cleared when dlerror is called
+///
+
+int main()
+{
+       // try to non-existent library
+       void* handle1 = dlopen("frobulite", RTLD_LAZY);
+       if ( handle1 != NULL ) {
+               FAIL("dlerror-clear: dlopen(\"frobulite\", RTLD_LAZY) succeeded but should have failed");
+               exit(0);
+       }
+       
+       // verify there is an error message
+       const char* msg = dlerror();
+       if ( msg == NULL ) {
+               FAIL("dlerror-clear: dlerror() returned NULL but should have returned an error message");
+               exit(0);
+       }
+       
+       // verify error message was cleared
+       const char* msg2 = dlerror();
+       if ( msg2 != NULL ) {
+               FAIL("dlerror-clear: dlerror() returned message but should have returned NULL");
+               exit(0);
+       }
+       
+       PASS("dlerror-clear");
+       return 0;
+}
diff --git a/unit-tests/test-cases/dlerror/Makefile b/unit-tests/test-cases/dlerror/Makefile
new file mode 100644 (file)
index 0000000..7337131
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main 
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/dlerror/main.c b/unit-tests/test-cases/dlerror/main.c
new file mode 100644 (file)
index 0000000..71ed8ab
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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 <string.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// This tests that the dlerror message is kept per thread
+///
+
+static void* work(void* arg)
+{
+       const char* str = (char*)arg;
+       for(int i=0; i < 1000; ++i) {
+               //fprintf(stderr, "dlopen(%s)\n", str);
+               void* handle = dlopen(str, RTLD_LAZY);
+               if ( handle != NULL ) {
+                       FAIL("dlopen(%s) unexpectedly succeeded", str);
+                       exit(0);
+               }
+               char* msg = dlerror();
+               //fprintf(stderr, "dlopen(%s) => %s\n", str, msg);
+               if ( (msg == NULL) || (strstr(msg, str) == NULL) ) {
+                       FAIL("dlerror() did not contain library name that could not be loaded", str);
+                       exit(0);
+               }
+               
+       
+       }
+       return 0;
+}
+
+
+
+int main()
+{
+       dlsym(RTLD_DEFAULT, "foobar");
+       //fprintf(stderr, "%s\n", dlerror());
+
+       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);
+       
+       PASS("dlerror-thread-test");
+       return 0;
+}
diff --git a/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/Makefile b/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/Makefile
new file mode 100644 (file)
index 0000000..aee8633
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = `pwd`
+
+run: all
+       ./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} -dynamiclib foo.c -o libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+       
+       
+
diff --git a/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/foo.c b/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/foo.c
new file mode 100644 (file)
index 0000000..fea884b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/main.c b/unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/main.c
new file mode 100644 (file)
index 0000000..b86c5e5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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()
+
+
+///
+/// When dlopen(NULL, RTLD_FIRST) is called, 
+/// any dlsym() looks against that handle should only look in 
+/// the main executable, and not subsequent images.
+///
+
+
+struct info
+{
+       const char* path;
+       void*           handle;
+};
+typedef struct info info;
+
+static info dlopen_or_fail(const char* path, int options)
+{
+       info result;
+       result.path = path;
+       result.handle = dlopen(path, options);
+       if ( result.handle == NULL ) {
+               FAIL("dlsym-NULL-RTLD_FIRST: dlopen(\"%s\") failed: %s", path, dlerror());
+               exit(0);
+       }
+       //fprintf(stderr, "dlopen(%s, 0x%0X) => %p\n", path, options, result.handle);
+       return result;
+}
+
+static void dlsym_should_fail(info hp, const char* symbol)
+{
+       void* sym = dlsym(hp.handle, symbol);
+       if ( sym != NULL ) {
+               FAIL("dlsym-NULL-RTLD_FIRST: dlsym(handle-%s, \"%s\") should have failed", hp.path, symbol);
+               exit(0);
+       }
+}
+
+static void dlsym_should_succeed(info hp, const char* symbol)
+{
+       void* sym = dlsym(hp.handle, symbol);
+       if ( sym == NULL ) {
+               FAIL("dlsym-NULL-RTLD_FIRST: dlsym(handle-%s, \"%s\") failed", hp.path, symbol);
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       int result;
+       info mainFirst          = dlopen_or_fail(NULL, RTLD_FIRST);
+       info mainDefault        = dlopen_or_fail(NULL, 0);
+               
+       dlsym_should_succeed(mainFirst, "main_foo");
+       dlsym_should_fail(mainFirst, "foo");
+       
+       dlsym_should_succeed(mainDefault, "main_foo");
+       dlsym_should_succeed(mainDefault, "foo");
+       
+       result = dlclose(mainFirst.handle);
+       if ( result != 0 ) {
+               FAIL("dlsym-NULL-RTLD_FIRST: dlclose(mainFirst.handle) failed: %s", dlerror());
+               exit(0);
+       }
+       result = dlclose(mainDefault.handle);
+       if ( result != 0 ) {
+               FAIL("dlsym-NULL-RTLD_FIRST: dlclose(mainDefault.handle) failed: %s", dlerror());
+               exit(0);
+       }
+
+       PASS("dlsym-NULL-RTLD_FIRST");
+       return EXIT_SUCCESS;
+}
+
+
+void main_foo() {}
+
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_FIRST/Makefile b/unit-tests/test-cases/dlopen-RTLD_FIRST/Makefile
new file mode 100644 (file)
index 0000000..170c483
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = `pwd`
+
+run: all
+       ./main
+
+all: main 
+
+main : main.c foo.bundle bar.bundle libfoo.dylib libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+foo.bundle : foo.c libbase.dylib
+       ${CC} ${CCFLAGS} -bundle foo.c libbase.dylib -o foo.bundle
+
+bar.bundle : bar.c libbase.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib bar.c libbase.dylib -o bar.bundle
+
+libfoo.dylib : foo.c libbase.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c libbase.dylib  -o libfoo.dylib
+
+libbar.dylib : bar.c libbase.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib bar.c libbase.dylib -o libbar.dylib -sub_library libbase
+
+libbase.dylib : base.c
+       ${CC} ${CCFLAGS} -dynamiclib base.c -o libbase.dylib -install_name ${PWD}/libbase.dylib
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle bar.bundle libfoo.dylib libbar.dylib libbase.dylib
+       
+       
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_FIRST/bar.c b/unit-tests/test-cases/dlopen-RTLD_FIRST/bar.c
new file mode 100644 (file)
index 0000000..7ef59fb
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int bar()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_FIRST/base.c b/unit-tests/test-cases/dlopen-RTLD_FIRST/base.c
new file mode 100644 (file)
index 0000000..87bb46c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int base()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_FIRST/foo.c b/unit-tests/test-cases/dlopen-RTLD_FIRST/foo.c
new file mode 100644 (file)
index 0000000..fea884b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_FIRST/main.c b/unit-tests/test-cases/dlopen-RTLD_FIRST/main.c
new file mode 100644 (file)
index 0000000..95d3ce4
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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()
+
+
+///
+/// When dlopen() is called with the RTLD_FIRST option,
+/// any dlsym() looks against that handle should only look in 
+/// that handle, and not subsequent images.
+///
+
+
+struct info
+{
+       const char* path;
+       void*           handle;
+};
+typedef struct info info;
+
+static info dlopen_or_fail(const char* path, int options)
+{
+       info result;
+       result.path = path;
+       result.handle = dlopen(path, options);
+       if ( result.handle == NULL ) {
+               FAIL("dlopen-RTLD_FIRST: dlopen(\"%s\") failed: %s", path, dlerror());
+               exit(0);
+       }
+       //fprintf(stderr, "dlopen(%s, 0x%0X) => %p\n", path, options, result.handle);
+       return result;
+}
+
+static void dlsym_should_fail(info hp, const char* symbol)
+{
+       void* sym = dlsym(hp.handle, symbol);
+       if ( sym != NULL ) {
+               FAIL("dlopen-RTLD_FIRST: dlsym(handle-%s, \"%s\") should have failed", hp.path, symbol);
+               exit(0);
+       }
+}
+
+static void dlsym_should_succeed(info hp, const char* symbol)
+{
+       void* sym = dlsym(hp.handle, symbol);
+       if ( sym == NULL ) {
+               FAIL("dlopen-RTLD_FIRST: dlsym(handle-%s, \"%s\") failed", hp.path, symbol);
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       info libFooFirst = dlopen_or_fail("libfoo.dylib", RTLD_FIRST);
+       info libFoo      = dlopen_or_fail("libfoo.dylib", 0);
+       
+       info libBarFirst = dlopen_or_fail("libbar.dylib", RTLD_FIRST);
+       info libBar      = dlopen_or_fail("libbar.dylib", 0);
+       
+       dlsym_should_succeed(libFooFirst, "foo");
+       dlsym_should_fail(libFooFirst, "base");
+       dlsym_should_fail(libFooFirst, "bar");
+       
+       dlsym_should_succeed(libFoo, "foo");
+       dlsym_should_succeed(libFoo, "base");
+                       
+       dlsym_should_succeed(libBarFirst, "bar");
+       dlsym_should_succeed(libBarFirst, "base");      // libbar re-exports libbase
+       dlsym_should_fail(libBarFirst, "foo");
+       
+       dlsym_should_succeed(libBar, "bar");
+       dlsym_should_succeed(libBar, "base");
+
+
+
+       info bundleFooFirst = dlopen_or_fail("foo.bundle", RTLD_FIRST);
+       info bundleFoo      = dlopen_or_fail("foo.bundle", 0);
+       
+       info bundleBarFirst = dlopen_or_fail("bar.bundle", RTLD_FIRST);
+       info bundleBar      = dlopen_or_fail("bar.bundle", 0);
+       
+       dlsym_should_succeed(bundleFooFirst, "foo");
+       dlsym_should_fail(bundleFooFirst, "base");
+       dlsym_should_fail(bundleFooFirst, "bar");
+       
+       dlsym_should_succeed(bundleFoo, "foo");
+       dlsym_should_succeed(bundleFoo, "base");
+                       
+       dlsym_should_succeed(bundleBarFirst, "bar");
+       dlsym_should_fail(bundleBarFirst, "base");
+       dlsym_should_fail(bundleBarFirst, "foo");
+       
+       dlsym_should_succeed(bundleBar, "bar");
+       dlsym_should_succeed(bundleBar, "base");
+
+
+       PASS("dlsym-RTLD_FIRST bundle and dylib");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/Makefile b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/Makefile
new file mode 100644 (file)
index 0000000..3cbb8e5
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# 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
+
+
+###
+### main links with hide/libfoo.dylib
+### main is run with DYLD_FALLBACK_LIBRARY_PATH pointing to hide
+### main calls dlopen("/foo/bar/libfoo.dylib", RTLD_NOLOAD)
+### dlopen should *not* find the already loaded libfoo.dylib because
+### it is only supposed to search existing loaded images for one
+### with a matching path.
+###
+
+
+run: all
+       export DYLD_FALLBACK_LIBRARY_PATH=hide && ./main /foo/bar/libfoo.dylib
+
+all: main 
+
+main : main.c hide/libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c hide/libfoo.dylib -o main 
+
+hide/libfoo.dylib : foo.c
+       mkdir -p hide
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o hide/libfoo.dylib
+
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main hide
+       
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/foo.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/foo.c
new file mode 100644 (file)
index 0000000..81f7dcf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/main.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/main.c
new file mode 100644 (file)
index 0000000..f629da7
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 <string.h>
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// This tests that RTLD_NOLOAD does not find an image via a fallback path
+///
+
+
+int main(int argc, const char* argv[])
+{
+       const char* path = argv[1];
+       void* handle = dlopen(path, RTLD_NOLOAD);
+       if ( handle != NULL ) 
+               FAIL("dlopen-RTLD_NOLOAD-fallback, dlopen(% RTLD_NOLOAD) should have failed");
+       else
+               PASS("dlopen-RTLD_NOLOAD-fallback");
+               
+       return 0;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/Makefile b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/Makefile
new file mode 100644 (file)
index 0000000..3bb5738
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main 
+
+all: main 
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+
+libfoo.dylib : foo.c libbar.dylib libbaz.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c libbar.dylib libbaz.dylib -o libfoo.dylib
+
+libbar.dylib : bar.c libbase.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -I${TESTROOT}/include libbase.dylib -o libbar.dylib
+
+libbaz.dylib : baz.c libbase.dylib
+       ${CC} ${CCFLAGS} -dynamiclib baz.c libbase.dylib -o libbaz.dylib
+
+libbase.dylib : base.c
+       ${CC} ${CCFLAGS} -dynamiclib base.c -o libbase.dylib
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib libbaz.dylib libbase.dylib
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/bar.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/bar.c
new file mode 100644 (file)
index 0000000..62fdfec
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdbool.h>
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern bool bazInitialized();
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+       if ( bazInitialized() ) {
+               FAIL("dlopen-RTLD_NOLOAD-in-initializer baz initialized too early");
+               exit(0);
+       }
+
+       // calling dlopen with RTLD_NOLOAD.
+       // this should not cause initialzers to run.
+       // in particular, baz should be be initialized
+       dlopen("libbaz.dylib", RTLD_NOLOAD);
+
+       if ( bazInitialized() ) {
+               FAIL("dlopen-RTLD_NOLOAD-in-initializer baz initialized by dlopen");
+               exit(0);
+       }
+}
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/base.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/base.c
new file mode 100644 (file)
index 0000000..3bcd164
--- /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 <stdbool.h>
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+static bool inited = false;
+
+void setBazInitialized() { inited = true; }
+
+bool bazInitialized() { return inited; }
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/baz.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/baz.c
new file mode 100644 (file)
index 0000000..6a80314
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 <stdbool.h>
+#include <dlfcn.h>
+
+extern void setBazInitialized();
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+       setBazInitialized();
+}
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/foo.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/foo.c
new file mode 100644 (file)
index 0000000..1e61ab3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 <stdbool.h>
+#include <dlfcn.h>
+
+
+bool foo()
+{
+       return true;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/main.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/main.c
new file mode 100644 (file)
index 0000000..9b67e37
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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> 
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+typedef bool (*fooProc)(void);
+
+int main()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"libfoo.dylib\") failed with: %s", dlerror());
+               exit(0);
+       }
+               
+       dlclose(handle);
+       
+       PASS("dlopen-RTLD_NOLOAD-in-initializer");
+
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/Makefile b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/Makefile
new file mode 100644 (file)
index 0000000..92a0b79
--- /dev/null
@@ -0,0 +1,59 @@
+##
+# 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
+
+
+###
+### Test that RTLD_NOLOAD finds existing image 
+### even when symlinks are used to obscure it
+###
+
+run: all
+       ./main libfoosym.dylib
+       ./main2 libbar.dylib
+
+
+all: main main2 libfoosym.dylib
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+       
+libfoosym.dylib : libfoo.dylib
+       ln -sf libfoo.dylib libfoosym.dylib
+
+libfoo.dylib : foo.c
+       ${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 
+
+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 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main2 libfoo.dylib libfoosym.dylib libbar.dylib libbarsym.dylib
+       
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/bar.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/bar.c
new file mode 100644 (file)
index 0000000..7fe6403
--- /dev/null
@@ -0,0 +1 @@
+int bar() { return 0; }
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/foo.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/foo.c
new file mode 100644 (file)
index 0000000..c58fc07
--- /dev/null
@@ -0,0 +1,2 @@
+int foo() { return 0; }
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/main.c b/unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/main.c
new file mode 100644 (file)
index 0000000..4ce752c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 <string.h>
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// This tests that RTLD_NOLOAD finds existing images
+///
+
+
+int main(int argc, const char* argv[])
+{
+       // main links against libfoo.dylib, so it is already loaded
+       // libbar.dylib is a symlink to libfoo.dylib, so it should succeed
+       void* handle = dlopen(argv[1], RTLD_NOLOAD);
+       if ( handle != NULL )
+               PASS("dlopen-RTLD_NOLOAD-symlink");
+       else
+               FAIL("dlopen-RTLD_NOLOAD-symlink");
+       return 0;
+}
index 7ce2f893d4c43e9069b0acaa5dde1f46bba61716..f877537cbb908aa5bf211cc0ff8177842ae6b2a7 100644 (file)
@@ -31,7 +31,7 @@ static void trySO(const char* path)
 {
        void* handle = dlopen(path, RTLD_LAZY);
        if ( handle == NULL ) {
-               FAIL("dlopen(\"%s\") failed", path);
+               FAIL("dlopen(\"%s\") failed with: %s", path, dlerror());
                exit(0);
        }
        
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/Makefile b/unit-tests/test-cases/dlopen-dyld-locking/Makefile
new file mode 100644 (file)
index 0000000..9902a73
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main libbar.dylib
+
+main : main.c libfoo.dylib libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbase.dylib
+
+libfoo.dylib : foo.c libbase.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c libbase.dylib  -o libfoo.dylib
+
+libbar.dylib : bar.c 
+       ${CC} ${CCFLAGS} -dynamiclib bar.c  -o libbar.dylib
+
+libbase.dylib : base.c
+       ${CC} ${CCFLAGS} -dynamiclib base.c -o libbase.dylib   -I${TESTROOT}/include 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib libbase.dylib
+       
+       
+
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/bar.c b/unit-tests/test-cases/dlopen-dyld-locking/bar.c
new file mode 100644 (file)
index 0000000..0531aa2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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@
+ */
+
+
+void __attribute__((constructor)) myInit()
+{
+  //    printf("in bar\n");
+}
+
+
+
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/base.c b/unit-tests/test-cases/dlopen-dyld-locking/base.c
new file mode 100644 (file)
index 0000000..4f842dc
--- /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@
+ */
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+static pthread_mutex_t sBarrierMutex;
+static pthread_cond_t  sBarrierFree;
+
+static volatile int sValue = 0;
+
+static void __attribute__((constructor)) myinit()
+{
+       pthread_mutex_init(&sBarrierMutex, NULL);
+       pthread_cond_init(&sBarrierFree, NULL);
+}
+
+void waitForState(int value)
+{
+       pthread_mutex_lock(&sBarrierMutex);
+       while ( sValue < value ) {
+               struct timeval        tvNow;
+               struct timespec       tsTimeout;                
+               gettimeofday(&tvNow, NULL);
+               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");
+                       exit(0);
+               }
+       }
+       pthread_mutex_unlock(&sBarrierMutex);
+}
+
+
+void setState(int value)
+{
+       pthread_mutex_lock(&sBarrierMutex);
+       sValue = value; 
+       pthread_cond_broadcast(&sBarrierFree);
+       pthread_mutex_unlock(&sBarrierMutex);
+}
+
+
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/base.h b/unit-tests/test-cases/dlopen-dyld-locking/base.h
new file mode 100644 (file)
index 0000000..f1aef79
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern void waitForState(int);
+extern void setState(int);
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/foo.c b/unit-tests/test-cases/dlopen-dyld-locking/foo.c
new file mode 100644 (file)
index 0000000..5753fa5
--- /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 "base.h"
+
+void __attribute__((constructor)) myInit()
+{
+       setState(1);
+       waitForState(2);
+}
+
+
+
diff --git a/unit-tests/test-cases/dlopen-dyld-locking/main.c b/unit-tests/test-cases/dlopen-dyld-locking/main.c
new file mode 100644 (file)
index 0000000..7952613
--- /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@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include "base.h"
+
+
+///
+/// This test verifies that dlopen() releases the dyld lock 
+/// while initializers are run. 
+/// 
+///
+
+
+static void* work(void* arg)
+{
+       waitForState(1);
+       dlopen("libbar.dylib", RTLD_LAZY);              // dladdr() will hang until dyld lock is released
+       setState(2);                            // the initializer in libfoo.dylib is block waiting for state 2
+       return NULL;
+}
+
+
+int main()
+{
+       pthread_t otherThread;
+       if ( pthread_create(&otherThread, NULL, work, NULL) != 0 ) {
+               FAIL("dlopen-dyld-locking: pthread_create failed");
+               exit(0);
+       }
+
+
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen-dyld-locking: dlopen(\"libfoo.dylib\") failed: %s", dlerror());
+               exit(0);
+       }
+
+       PASS("dlsym-dyld-locking");
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/dlopen-from-anonymous-code/Makefile b/unit-tests/test-cases/dlopen-from-anonymous-code/Makefile
new file mode 100644 (file)
index 0000000..cc201a6
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main foo.bundle 
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+foo.bundle : foo.c
+       ${CC} ${CCFLAGS} -bundle foo.c -o foo.bundle
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle 
+
diff --git a/unit-tests/test-cases/dlopen-from-anonymous-code/foo.c b/unit-tests/test-cases/dlopen-from-anonymous-code/foo.c
new file mode 100644 (file)
index 0000000..fea884b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-from-anonymous-code/main.c b/unit-tests/test-cases/dlopen-from-anonymous-code/main.c
new file mode 100644 (file)
index 0000000..8dfe72f
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006-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 <string.h> // memcpy
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <libkern/OSCacheControl.h> // sys_icache_invalidate
+#include <sys/mman.h> // for mprotext
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+void* calldlopen(const char* path, int mode, void* (*dlopen_proc)(const char* path, int mode))
+{
+       return (*dlopen_proc)(path, mode);
+}
+
+//
+// try calling dlopen() from code not owned by dyld
+//
+int main()
+{
+       void* codeBlock = malloc(4096);
+       memcpy(codeBlock, &calldlopen, 4096);
+       sys_icache_invalidate(codeBlock, 4096);
+       mprotect(codeBlock, 4096, PROT_READ | PROT_EXEC);
+       //fprintf(stderr, "codeBlock=%p\n", codeBlock);
+       
+       void* (*caller)(const char* path, int mode, void* (*dlopen_proc)(const char* path, int mode)) = codeBlock;
+       
+       void* handle = (*caller)("foo.bundle", RTLD_LAZY, &dlopen);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", "foo.bundle", 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 ) {
+               FAIL("dlclose(handle) returned %d", result);
+               exit(0);
+       }
+  
+       PASS("dlopen-from-anonymous-code");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-in-initializer/Makefile b/unit-tests/test-cases/dlopen-in-initializer/Makefile
new file mode 100644 (file)
index 0000000..d3dd9c2
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main || echo "FAIL dlopen-in-initializer" 
+
+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/dlopen-in-initializer/foo.c b/unit-tests/test-cases/dlopen-in-initializer/foo.c
new file mode 100644 (file)
index 0000000..3bef65e
--- /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 on a non-existent file to verify error handled cleanly
+       dlopen("/no_such/path", RTLD_LAZY);
+}
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-in-initializer/main.c b/unit-tests/test-cases/dlopen-in-initializer/main.c
new file mode 100644 (file)
index 0000000..bdc6dcf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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()
+
+
+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);
+               }
+       }
+
+}
+
+
+
+int main()
+{
+       trySO("test.bundle");
+       trySO("test.dylib");
+  
+       PASS("dlopen-in-initializer");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-up/Makefile b/unit-tests/test-cases/dlopen-init-dlopen-up/Makefile
new file mode 100644 (file)
index 0000000..723ff97
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main || echo "FAIL dlopen-init-dlopen-up" 
+
+all: main 
+
+main : main.c libbar.dylib
+       ${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 libfoo.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib
+
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-up/bar.c b/unit-tests/test-cases/dlopen-init-dlopen-up/bar.c
new file mode 100644 (file)
index 0000000..15b1327
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+extern int foo();
+
+int bar() { return foo(); }
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-up/foo.c b/unit-tests/test-cases/dlopen-init-dlopen-up/foo.c
new file mode 100644 (file)
index 0000000..a816ea8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 <dlfcn.h>
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+       // this is an upward dependency since libbar depends on libfoo
+       dlopen("libbar.dylib", RTLD_LAZY);
+}
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-up/main.c b/unit-tests/test-cases/dlopen-init-dlopen-up/main.c
new file mode 100644 (file)
index 0000000..d9a2c70
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 <dlfcn.h>
+
+#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 ) {
+               FAIL("dlclose(handle) returned %d", result);
+               exit(0);
+       }
+
+}
+
+
+
+int main()
+{
+       trySO("libfoo.dylib");
+  
+       PASS("dlopen-init-dlopen-up");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen/Makefile b/unit-tests/test-cases/dlopen-init-dlopen/Makefile
new file mode 100644 (file)
index 0000000..4a35562
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main || echo "FAIL dlopen-init-dlopen" 
+
+all: main 
+
+main : main.c libbar.dylib libfoo.dylib
+       ${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 libbar.dylib libfoo.dylib
+
diff --git a/unit-tests/test-cases/dlopen-init-dlopen/bar.c b/unit-tests/test-cases/dlopen-init-dlopen/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/foo.c b/unit-tests/test-cases/dlopen-init-dlopen/foo.c
new file mode 100644 (file)
index 0000000..78ab60d
--- /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 foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen/main.c b/unit-tests/test-cases/dlopen-init-dlopen/main.c
new file mode 100644 (file)
index 0000000..9f1c5fb
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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()
+
+
+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);
+               }
+       }
+
+}
+
+
+
+int main()
+{
+       trySO("libfoo.dylib");
+  
+       PASS("dlopen-init-dlopen");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-init-up/Makefile b/unit-tests/test-cases/dlopen-init-up/Makefile
new file mode 100644 (file)
index 0000000..3991ab4
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main || echo "FAIL dlopen-init-dlopen-up" 
+
+all: main 
+
+main : main.c libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib 
+
+
+libfoo.dylib : foo.c   
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+
+libbar.dylib : bar.c libfoo.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib
+
diff --git a/unit-tests/test-cases/dlopen-init-up/bar.c b/unit-tests/test-cases/dlopen-init-up/bar.c
new file mode 100644 (file)
index 0000000..15b1327
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+extern int foo();
+
+int bar() { return foo(); }
diff --git a/unit-tests/test-cases/dlopen-init-up/foo.c b/unit-tests/test-cases/dlopen-init-up/foo.c
new file mode 100644 (file)
index 0000000..77dd28f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <dlfcn.h>
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+       // this is an upward dependency since libbar depends on libfoo
+       // rdar://problem/5213017 
+       dlopen("libbar.dylib", RTLD_LAZY);
+}
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-up/main.c b/unit-tests/test-cases/dlopen-init-up/main.c
new file mode 100644 (file)
index 0000000..abdd5f1
--- /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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int main()
+{
+       PASS("dlopen-init-up");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen_preflight-basic/Makefile b/unit-tests/test-cases/dlopen_preflight-basic/Makefile
new file mode 100644 (file)
index 0000000..4b1d3e7
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+       ./main batch
+
+all: main foo.bundle bar.bundle bogus.bundle libbogus.dylib 
+
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+
+foo.bundle: foo.c libbar.dylib 
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle foo.c libbar.dylib  
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+bar.bundle: bar.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o bar.bundle bar.c  
+
+bogus.bundle :
+       echo "bogus" > bogus.bundle
+       
+libbogus.dylib :
+       echo "bogus" > libbogus.dylib 
+       
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle  libbar.dylib bar.bundle bogus.bundle libbogus.dylib 
+
diff --git a/unit-tests/test-cases/dlopen_preflight-basic/bar.c b/unit-tests/test-cases/dlopen_preflight-basic/bar.c
new file mode 100644 (file)
index 0000000..63c34e0
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar = 10;
diff --git a/unit-tests/test-cases/dlopen_preflight-basic/foo.c b/unit-tests/test-cases/dlopen_preflight-basic/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/dlopen_preflight-basic/main.c b/unit-tests/test-cases/dlopen_preflight-basic/main.c
new file mode 100644 (file)
index 0000000..4fdec0e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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>  // 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()
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "bar" in its name from loading.
+//
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //for (uint32_t i=0; i < infoCount; ++i) {
+       //      fprintf(stderr, "batch mapped: %d/%d %s\n", i, infoCount, info[i].imageFilePath);
+       //}
+       for (uint32_t i=0; i < infoCount; ++i) {
+               if ( strstr(info[i].imageFilePath, "bar") != NULL )
+                       return "cannot load bar";
+       }
+       return NULL;
+}
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+       if ( strstr(info[0].imageFilePath, "bar") != NULL )
+               return "can't load bar";
+       return NULL;
+}
+
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images are mapped
+       if ( argc > 1 )
+               dyld_register_image_state_change_handler(dyld_image_state_dependents_mapped, true, batchMappedHandler);
+       else
+               dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+       
+       if ( dlopen_preflight("foo.bundle") ) {
+               FAIL("dlopen_preflight-basic foo.bundle should not be loadable");
+               exit(0);
+       }
+       //fprintf(stderr, "foo.bundle, dlerror: %s\n", dlerror());
+
+       if ( dlopen_preflight("bar.bundle") ) {
+               FAIL("dlopen_preflight-basic bar.bundle should not be loadable");
+               exit(0);
+       }
+       //fprintf(stderr, "bar.bundle, dlerror: %s\n", dlerror());
+
+       if ( dlopen_preflight("bogus.bundle") ) {
+               FAIL("dlopen_preflight-basic bogus.bundle should not be loadable");
+               exit(0);
+       }
+       //fprintf(stderr, "bogus.bundle, dlerror: %s\n", dlerror());
+
+       if ( ! dlopen_preflight("/usr/lib/libSystem.B.dylib") ) {
+               FAIL("dlopen_preflight-basic libSystem should be loadable, but got: %s", dlerror());
+               exit(0);
+       }
+
+       
+       PASS("dlopen_preflight-basic");
+               
+       return EXIT_SUCCESS;
+}
index 491d9f4833e9bef91d452fd8efed04de16d182fb..980ce61550b2c05265609356070c3783056f863f 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PROG = ./main
+
+ifeq "ppc" "$(ARCH)"
+       MACHINE =  $(shell arch)
+       ifeq "i386" "$(MACHINE)"
+               PROG = /usr/bin/true
+       endif
+endif
+
+
+
 run: all
-       ${TESTROOT}/bin/exit-zero-pass.pl "dlsym-RTLD_NEXT-missing with circular libraries" "dlsym-RTLD_NEXT-missing with circular libraries" ./main
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlsym-RTLD_NEXT-missing with circular libraries" "dlsym-RTLD_NEXT-missing with circular libraries" ${PROG}
 
-all: main 
+all:  main
 
 main : main.c foo1.dylib
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo1.dylib
index ce7c3a82f8006abced9b8f1552614df5ee167f9c..8c137c6e30365e364700d2a1066c2e0a6629cb51 100644 (file)
@@ -37,7 +37,6 @@
 /// We also check that this works in the main executable.
 ///
 
-#ifdef RTLD_SELF 
 
 int foo()
 {
@@ -63,12 +62,10 @@ static void trySO(const char* pathToLoad)
        (*sym)();       
 }
 
-#endif
 
 
 int main()
 {
-#ifdef RTLD_SELF 
        trySO("test.bundle");
        trySO("test.dylib");
 
@@ -77,8 +74,5 @@ int main()
        }
        
        PASS("dlsym-RTLD_SELF bundle and dylib");
-#else
-       XFAIL("dlsym-RTLD_SELF not implemented");
-#endif
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/dyld-func-lookup/Makefile b/unit-tests/test-cases/dyld-func-lookup/Makefile
new file mode 100644 (file)
index 0000000..56ebee5
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main test.bundle test.dylib
+
+main : main.c foo.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.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/dyld-func-lookup/foo.c b/unit-tests/test-cases/dyld-func-lookup/foo.c
new file mode 100644 (file)
index 0000000..00b5af3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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>
+
+extern bool _dyld_func_lookup(const char* dyld_func_name, void** address);
+
+
+
+bool check_dyld_func_lookup()
+{
+       void* address;
+       
+       // dlopen does not exist, something is wrong
+       if ( ! _dyld_func_lookup("__dyld_dlopen", &address) )
+               return false;
+               
+       // if a garbage string returns true, something is wrong
+       if ( _dyld_func_lookup("blablah", &address) )
+               return false;
+       
+       // looks good
+       return true;
+}
diff --git a/unit-tests/test-cases/dyld-func-lookup/main.c b/unit-tests/test-cases/dyld-func-lookup/main.c
new file mode 100644 (file)
index 0000000..270e343
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <stdbool.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern bool check_dyld_func_lookup();
+
+typedef bool (*proc)(void);
+
+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);
+       }
+       
+       proc sym = (proc)dlsym(handle, "check_dyld_func_lookup");
+       if ( sym == NULL ) {
+               FAIL("dlsym(handle, \"foo\") failed");
+               exit(0);
+       }
+       
+       if ( sym == &check_dyld_func_lookup )
+               FAIL("found same check_dyld_func_lookup as in main executable");
+       
+       if ( ! (*sym)() )
+               FAIL("check_dyld_func_lookup failed for %s", path);
+       
+       dlclose(handle);
+}
+
+
+
+int main()
+{
+       if ( ! check_dyld_func_lookup() )
+               FAIL("check_dyld_func_lookup failed for main executable");
+
+       trySO("test.bundle");
+       trySO("test.dylib");
+  
+       PASS("dyld-func-lookup");
+       return EXIT_SUCCESS;
+}
index 4eb418a55036c2eb5c7a753dd452ac6fd68ee3e6..723309619c3f145def018b2d9bb7494f4dbd7aa0 100644 (file)
@@ -27,7 +27,7 @@ run: all
        ${TESTROOT}/bin/exit-zero-pass.pl "_dyld_launched_prebound() was implemented" "_dyld_launched_prebound() was not implemented" ./main
 
 all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c
 
 clean:
        ${RM} ${RMFLAGS} *~ main
index b4bf269763af58ac2d477bcad2bb94dadeab5800..a64d5a26c4517b224f30e67ad1e98d5d9b6b3cf8 100644 (file)
@@ -27,7 +27,7 @@
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 int
-main(int argc, char **argv, char **envp, char**appl)
+main(int argc, const char* argv[])
 {
   _dyld_launched_prebound();
   return EXIT_SUCCESS;
index 35f422d56e304d4475c85480da5e32a1eb52db58..98fd14df8ddf34dfa47f625fec06aada056916b3 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@
 # 
@@ -27,7 +27,7 @@ run: all
        ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main
 
 all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -pagezero_size 0x40000000
 
 clean:
        ${RM} ${RMFLAGS} main
index ad5b149dcab7d2044e06d22caf2dcf2a093b0250..957dfef08388fdedea2f202b28221bd54849efb4 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@
  * 
 // This builds an executable that is just big enough to force dyld to slide a bit
 //
 
-#define ARRAY_SIZE 301800000
+#define ARRAY_SIZE 335400000
 
 int bigarray1[ARRAY_SIZE];
-int bigarray2[ARRAY_SIZE];
 
 int
 main()
diff --git a/unit-tests/test-cases/executable-image-index/Makefile b/unit-tests/test-cases/executable-image-index/Makefile
new file mode 100644 (file)
index 0000000..ae7321e
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# 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
+
+run: all
+       #export DYLD_INSERT_LIBRARIES=libfoo.dylib && ./main
+       ./main
+
+all: main  libfoo.dylib
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -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/executable-image-index/foo.c b/unit-tests/test-cases/executable-image-index/foo.c
new file mode 100644 (file)
index 0000000..83c0b65
--- /dev/null
@@ -0,0 +1,2 @@
+void foo() { }
+
diff --git a/unit-tests/test-cases/executable-image-index/main.c b/unit-tests/test-cases/executable-image-index/main.c
new file mode 100644 (file)
index 0000000..315ea8e
--- /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 <stdint.h>
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <mach-o/ldsyms.h>
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// many apps rely on _dyld_get_image_header(0) being the main executable
+// DYLD_INSERT_LIBRARIES can change the order
+
+extern const struct mach_header __dso_handle;
+
+int main()
+{
+       if ( _dyld_get_image_header(0) == &__dso_handle )
+               PASS("executable-image-index");
+       else
+               FAIL("executable-image-index: index(0) is %s", _dyld_get_image_name(0));
+               
+       return EXIT_SUCCESS;
+}
index f2a630d2a1763a9057fc9cfbe4f8166d8ce25c29..6fd0158a349c2e787ef0ecf16e6bc0abd241f361 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -24,23 +24,21 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 run: all
-       export HOME="`pwd`/hide" && ./main user
-       export HOME="`pwd`/hide" && ./main-suid root
-
-all: main main-suid
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "fallback-with-suid" "fallback-with-suid" ./main-suid
+       
+all: main-suid
 
-main: main.c hide/lib/libfoo.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
        
 main-suid: main
        cp main main-suid
        sudo chown root main-suid
        sudo chmod 4755 main-suid
 
-hide/lib/libfoo.dylib : foo.c
-       mkdir -p hide/lib
-       ${CC} ${CCFLAGS} foo.c -dynamiclib -o hide/lib/libfoo.dylib
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /bogus/libz.dylib
 
 clean:
-       ${RM} ${RMFLAGS} *~ main main-suid hide
+       ${RM} ${RMFLAGS} *~ main main-suid libfoo.dylib
 
index fa1d6fe0ba92cd1efb07d958d82ee66426945ddd..4ecb9310f121b76ff5417aea8d2d526712a8b297 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,3 +21,5 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+void compress() {}
+
index a0ce919778c147ab4da5e53652500b5750d9cbb3..bb793934cf6eb2e160ae3b4e21d66e953d63e1ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 // binaries set to run as some other user id never use $HOME part of fallback-path
 //
 
+extern void compress();
+
 int main(int argc, const char *argv[])
 {
-       const struct mach_header* mh = NSAddImage("/foo/bar/libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
-
-       if ( strcmp(argv[1], "root") == 0 ) {
-               if ( mh == NULL )
-                       PASS("fallback-with-suid root");
-               else
-                       FAIL("fallback-with-suid root");
-       }
-       else {
-               if ( mh != NULL )
-                       PASS("fallback-with-suid user");
-               else
-                       FAIL("fallback-with-suid user");
-       }
+       if ( &compress != NULL )
+               FAIL("fallback-with-suid root");
        
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/flat-insert/Makefile b/unit-tests/test-cases/flat-insert/Makefile
new file mode 100644 (file)
index 0000000..ff17213
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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 inserted libraries override with flat namespace
+
+run: all
+       export DYLD_INSERT_LIBRARIES="libfoo.dylib" && ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -flat_namespace -Wl,-interposable
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/flat-insert/foo.c b/unit-tests/test-cases/flat-insert/foo.c
new file mode 100644 (file)
index 0000000..2d68edf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 <stdlib.h>
+
+
+int foo()
+{
+       return 42;
+}
+
diff --git a/unit-tests/test-cases/flat-insert/main.c b/unit-tests/test-cases/flat-insert/main.c
new file mode 100644 (file)
index 0000000..160955c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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()
+
+extern int foo();
+
+int main(int argc, const char* argv[])
+{
+       if ( foo() == 42 ) 
+               PASS("flat-insert");
+       else
+               FAIL("flat-insert");
+       return EXIT_SUCCESS;
+}
+
+// inserted library has another copy of foo() that should
+// overridde this one and return 42
+int foo()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/flat-lookup-everywhere/Makefile b/unit-tests/test-cases/flat-lookup-everywhere/Makefile
deleted file mode 100644 (file)
index d1b99b5..0000000
+++ /dev/null
@@ -1,34 +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@
-##
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-run: all
-       DYLD_INSERT_LIBRARIES="/usr/lib/libMallocDebug.A.dylib" DYLD_FORCE_FLAT_NAMESPACE="" ./main
-
-all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -framework CoreFoundation -o main main.c
-
-clean:
-       ${RM} ${RMFLAGS} *~ main
-
diff --git a/unit-tests/test-cases/flat-lookup-everywhere/main.c b/unit-tests/test-cases/flat-lookup-everywhere/main.c
deleted file mode 100644 (file)
index fb2c2a1..0000000
+++ /dev/null
@@ -1,35 +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@
- */
-#include <stdio.h>  // fprintf(), NULL
-#include <stdlib.h> // exit(), EXIT_SUCCESS
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
-
-int
-main()
-{
-  CFStringRef string = CFStringCreateWithFormat(NULL, NULL, CFSTR(""));
-  PASS("flat-lookup-everywhere");
-  return EXIT_SUCCESS;
-}
index adf063df7dc3ca2b676aad572021ddd150e128c6..44cfad135b5827c20d5487021247dfefb1ad9d12 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all : main
 
 main: main.c
-       ${CC} main.c -o main  -I${TESTROOT}/include
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  main.c -o main  -I${TESTROOT}/include
 
 clean:
        ${RM} ${RMFLAGS} main
diff --git a/unit-tests/test-cases/image-state-change/Makefile b/unit-tests/test-cases/image-state-change/Makefile
new file mode 100644 (file)
index 0000000..b287606
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main foo.bundle
+
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+foo.bundle: foo.c libbar.dylib 
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle foo.c libbar.dylib  
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle  libbar.dylib
+
diff --git a/unit-tests/test-cases/image-state-change/bar.c b/unit-tests/test-cases/image-state-change/bar.c
new file mode 100644 (file)
index 0000000..63c34e0
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar = 10;
diff --git a/unit-tests/test-cases/image-state-change/foo.c b/unit-tests/test-cases/image-state-change/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-change/main.c b/unit-tests/test-cases/image-state-change/main.c
new file mode 100644 (file)
index 0000000..0a6673d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+static int singleMappedCount = 0;
+static int batchMappedCount = 0;
+
+
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       for (uint32_t i=0; i < infoCount; ++i) 
+               printf("batchMappedHandler(): %u/%u -> %s\n", i, infoCount, info[i].imageFilePath);
+       if ( state != dyld_image_state_dependents_mapped ) {
+               FAIL("image-state-change: batchMappedHandler passed state %d", state);
+               exit(0);
+       }
+       batchMappedCount += infoCount;
+       return NULL;
+}
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       printf("singleMappedHandler(%s)\n", info[0].imageFilePath);
+       if ( state != dyld_image_state_mapped ) {
+               FAIL("image-state-change: singleMappedHandler passed state %d", state);
+               exit(0);
+       }
+       if ( infoCount != 1 ) {
+               FAIL("image-state-change: singleMappedHandler given %d images", infoCount);
+               exit(0);
+       }
+       ++singleMappedCount;
+       return NULL;
+}
+
+static void loadAndUnLoad()
+{
+       void* handle = dlopen("foo.bundle", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("image-state-change: dlopen(foo.bundle) failed: %s", dlerror());
+               exit(0);
+       }
+               
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               FAIL("image-state-change: dlclose(handle) returned %d, %s", result, dlerror());
+               exit(0);
+       }
+}
+
+
+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);
+       // with batch mode we get notified of existing images, but not with single mode, so re-sync counts
+       batchMappedCount=0;
+       
+       loadAndUnLoad();
+
+       loadAndUnLoad();
+       
+       if ( singleMappedCount == batchMappedCount )
+               PASS("image-state-change");
+       else
+               FAIL("image-state-change: batch count=%d, single count=%d", batchMappedCount, singleMappedCount);
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-deny-OFI/Makefile b/unit-tests/test-cases/image-state-deny-OFI/Makefile
new file mode 100644 (file)
index 0000000..5ad9359
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+       ./main batch
+
+all: main foo.bundle bar.bundle foo2.bundle
+
+main: main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c 
+
+foo.bundle: foo.c libbar.dylib 
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle foo.c libbar.dylib  
+
+foo2.bundle: foo.c  
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo2.bundle foo.c  
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+bar.bundle: bar.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o bar.bundle bar.c  
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle  libbar.dylib bar.bundle foo2.bundle
+
diff --git a/unit-tests/test-cases/image-state-deny-OFI/bar.c b/unit-tests/test-cases/image-state-deny-OFI/bar.c
new file mode 100644 (file)
index 0000000..63c34e0
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar = 10;
diff --git a/unit-tests/test-cases/image-state-deny-OFI/foo.c b/unit-tests/test-cases/image-state-deny-OFI/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-deny-OFI/main.c b/unit-tests/test-cases/image-state-deny-OFI/main.c
new file mode 100644 (file)
index 0000000..3e1f341
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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>  // 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()
+
+static bool doneRegistering = false;
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "bar" in its name from loading.
+//
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       for (uint32_t i=0; i < infoCount; ++i) {
+               //fprintf(stderr, "batch mapped: %d %s\n", i, info[i].imageFilePath);
+               if ( strstr(info[i].imageFilePath, "bar") != NULL )
+                       return "can't load bar";
+       }
+       return NULL;
+}
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+       if ( strstr(info[0].imageFilePath, "bar") != NULL )
+               return "can't load bar";
+       return NULL;
+}
+
+
+
+static const char* singleInitializedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "singleInitializedHandler(%s)\n", info[0].imageFilePath);
+       if ( doneRegistering ) {
+               FAIL("image-state-deny something loaded");
+               exit(0);
+       }
+       return NULL;
+}
+
+//static const char* batchBoundHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+//{
+//     //for (uint32_t i=0; i < infoCount; ++i) 
+//     //      fprintf(stderr, "bound: %u %s\n", i, info[i].imageFilePath);
+//     return NULL;
+//}
+
+static void load(const char* name)
+{
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromFile(name, &ofi) == NSObjectFileImageSuccess ) {
+               NSModule mod = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+               if ( mod != NULL ) {
+                       FAIL("neither NSCreateObjectFileImageFromFile nor NSLinkModule failed but should have");
+                       if ( !NSDestroyObjectFileImage(ofi) ) {
+                               FAIL("NSDestroyObjectFileImage failed");
+                       }
+                       exit(0);
+               }
+               else {
+                       NSDestroyObjectFileImage(ofi);
+               }
+       }
+}
+
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images successfully loaded
+       dyld_register_image_state_change_handler(dyld_image_state_initialized, false, singleInitializedHandler);
+       doneRegistering = true;
+       
+       // tell dyld we want to know when images successfully loaded
+       //dyld_register_image_state_change_handler(dyld_image_state_bound, true, batchBoundHandler);
+
+       // tell dyld we want to know when images are mapped
+       if ( argc > 1 )
+               dyld_register_image_state_change_handler(dyld_image_state_dependents_mapped, true, batchMappedHandler);
+       else
+               dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+       
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromFile("foo2.bundle", &ofi) != NSObjectFileImageSuccess ) {
+               FAIL("NSCreateObjectFileImageFromFile failed for foo2.bundle");
+               exit(0);
+       }
+       
+       load("foo.bundle");
+
+       load("bar.bundle");
+       
+       if ( !NSDestroyObjectFileImage(ofi) ) {
+               FAIL("NSDestroyObjectFileImage failed for foo2.bundle");
+               exit(0);
+       }
+
+//     dlopen("/usr/lib/libz.1.2.3.dylib", RTLD_LAZY);
+       
+       PASS("image-state-deny");
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-deny-dlclose/Makefile b/unit-tests/test-cases/image-state-deny-dlclose/Makefile
new file mode 100644 (file)
index 0000000..ed88495
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+
+all: main
+
+main: main.c libfoo.dylib  libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib  foo.c 
+       
+libbase.dylib : base.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbase.dylib  base.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libbase.dylib 
+
diff --git a/unit-tests/test-cases/image-state-deny-dlclose/base.c b/unit-tests/test-cases/image-state-deny-dlclose/base.c
new file mode 100644 (file)
index 0000000..842e2e2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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>  
+
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //for (uint32_t i=0; i < infoCount; ++i) {
+       //      fprintf(stderr, "batch mapped: %d %s\n", i, info[i].imageFilePath);
+       //}
+       return NULL;
+}
+
+static void myregister() __attribute__((constructor));
+
+static void myregister()
+{
+       // tell dyld we want to know when images successfully loaded
+       dyld_register_image_state_change_handler(dyld_image_state_dependents_mapped, true, batchMappedHandler);
+}
diff --git a/unit-tests/test-cases/image-state-deny-dlclose/foo.c b/unit-tests/test-cases/image-state-deny-dlclose/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-deny-dlclose/main.c b/unit-tests/test-cases/image-state-deny-dlclose/main.c
new file mode 100644 (file)
index 0000000..e4756bb
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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>  // 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[])
+{
+       // open and close base
+       void* h1 = dlopen("libbase.dylib", RTLD_LAZY);
+       if ( h1 == NULL ) {
+               FAIL("image-state-deny-dlclose: can't dlopen libbase.dylib: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       dlclose(h1);
+       
+       // if base was unloaded, then this dlopen will jump to neverland
+       void* h2 = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( h2 == NULL ) {
+               FAIL("image-state-deny-dlclose: can't dlopen libfoo.dylib: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       void* h3 = dlopen("libbase.dylib", RTLD_LAZY);
+       if ( h3 == NULL ) {
+               FAIL("image-state-deny-dlclose: can't dlopen libbase.dylib: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       dlclose(h3);
+
+       dlclose(h2);
+               
+               
+       PASS("image-state-deny-dlclose");
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-deny/Makefile b/unit-tests/test-cases/image-state-deny/Makefile
new file mode 100644 (file)
index 0000000..4bff299
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+run: all
+       ./main
+       ./main batch
+
+all: main foo.bundle bar.bundle
+
+main: main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c 
+
+foo.bundle: foo.c libbar.dylib 
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle foo.c libbar.dylib  
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+bar.bundle: bar.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o bar.bundle bar.c  
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle  libbar.dylib bar.bundle
+
diff --git a/unit-tests/test-cases/image-state-deny/bar.c b/unit-tests/test-cases/image-state-deny/bar.c
new file mode 100644 (file)
index 0000000..63c34e0
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar = 10;
diff --git a/unit-tests/test-cases/image-state-deny/foo.c b/unit-tests/test-cases/image-state-deny/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-deny/main.c b/unit-tests/test-cases/image-state-deny/main.c
new file mode 100644 (file)
index 0000000..df8f1d9
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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>  // 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()
+
+static bool doneRegistering = false;
+
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "bar" in its name from loading.
+//
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       for (uint32_t i=0; i < infoCount; ++i) {
+               //fprintf(stderr, "batch mapped: %d %s\n", i, info[i].imageFilePath);
+               if ( strstr(info[i].imageFilePath, "bar") != NULL )
+                       return "can't load bar";
+       }
+       return NULL;
+}
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+       if ( strstr(info[0].imageFilePath, "bar") != NULL )
+               return "can't load bar";
+       return NULL;
+}
+
+
+
+static const char* singleInitializedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "singleInitializedHandler(%s)\n", info[0].imageFilePath);
+       if ( doneRegistering ) {
+               FAIL("image-state-deny something loaded");
+               exit(0);
+       }
+       return NULL;
+}
+
+//static const char* batchBoundHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+//{
+//     //for (uint32_t i=0; i < infoCount; ++i) 
+//     //      fprintf(stderr, "bound: %u %s\n", i, info[i].imageFilePath);
+//     return NULL;
+//}
+
+static void load(const char* name)
+{
+       void* handle = dlopen(name, RTLD_LAZY);
+       if ( handle != NULL ) {
+               FAIL("image-state-deny: dlopen(%s) should have failed", name);
+               exit(0);
+       }
+}
+
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images successfully loaded
+       dyld_register_image_state_change_handler(dyld_image_state_initialized, false, singleInitializedHandler);
+       doneRegistering = true;
+       
+       // tell dyld we want to know when images successfully loaded
+       //dyld_register_image_state_change_handler(dyld_image_state_bound, true, batchBoundHandler);
+
+       // tell dyld we want to know when images are mapped
+       if ( argc > 1 )
+               dyld_register_image_state_change_handler(dyld_image_state_dependents_mapped, true, batchMappedHandler);
+       else
+               dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+       
+       load("foo.bundle");
+
+       load("bar.bundle");
+       
+       //dlopen("/usr/lib/libz.1.2.3.dylib", RTLD_LAZY);
+       
+       PASS("image-state-deny");
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-dependents-initialized/Makefile b/unit-tests/test-cases/image-state-dependents-initialized/Makefile
new file mode 100644 (file)
index 0000000..91b2ef1
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
+
+run: all
+       ./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} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib  foo.c  libbar.dylib
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib
+
diff --git a/unit-tests/test-cases/image-state-dependents-initialized/bar.c b/unit-tests/test-cases/image-state-dependents-initialized/bar.c
new file mode 100644 (file)
index 0000000..3b6c323
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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 <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <stdbool.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+static enum { start, barDeps, bar, fooDeps, foo, mainDeps, main } step = start;
+
+
+static const char* depInitHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       if ( infoCount != 1 ) {
+               FAIL("image-state-dependents-initialized: depInitHandler infoCount != 1\n");
+               exit(0);
+       }
+
+       //fprintf(stderr, "depInitHandler(%s), state=%d\n", info[0].imageFilePath, step);
+
+       if ( (step == start) && (strstr(info[0].imageFilePath, "libbar.dylib") != NULL) )
+               step = barDeps;
+       else if ( (step == bar) && (strstr(info[0].imageFilePath, "libfoo.dylib") != NULL) )
+               step = fooDeps;
+       else if ( (step == foo) && (strstr(info[0].imageFilePath, "/main") != NULL) )
+               step = mainDeps;
+       else {
+               fprintf(stderr, "out of order depInitHandler\n");
+               exit(0);
+       }
+       
+
+       return NULL;
+}
+
+static const char* initHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       if ( infoCount != 1 ) {
+               FAIL("image-state-dependents-initialized: initHandler infoCount != 1\n");
+               exit(0);
+       }
+
+       //fprintf(stderr, "initHandler(%s), state=%d\n", info[0].imageFilePath, step);
+       bool isBar = (strstr(info[0].imageFilePath, "libbar.dylib") != NULL);
+       bool isFoo = (strstr(info[0].imageFilePath, "libfoo.dylib") != NULL);
+       bool isMain= (strstr(info[0].imageFilePath, "/main") != NULL);
+       
+       if ( isBar ) {
+               if ( step == barDeps ) {
+                       step = bar;
+               }
+               else {
+                       fprintf(stderr, "out of order initHandler bar\n");
+                       exit(0);
+               }
+       }
+       else if ( isFoo ) {
+               if ( step == fooDeps ) {
+                       step = foo;
+               }
+               else {
+                       fprintf(stderr, "out of order initHandler foo\n");
+                       exit(0);
+               }
+       }
+       else if ( isMain ) {
+               if ( step == mainDeps ) {
+                       step = main;
+               }
+               else {
+                       fprintf(stderr, "out of order initHandler main\n");
+                       exit(0);
+               }
+       }
+
+
+       return NULL;
+}
+
+
+
+
+void __attribute__((constructor)) setup_bar()
+{
+       // tell dyld we want to know when images are mapped
+       dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, false, depInitHandler);
+       dyld_register_image_state_change_handler(dyld_image_state_initialized, false, initHandler);
+}
+
+
+
diff --git a/unit-tests/test-cases/image-state-dependents-initialized/foo.c b/unit-tests/test-cases/image-state-dependents-initialized/foo.c
new file mode 100644 (file)
index 0000000..9584c6e
--- /dev/null
@@ -0,0 +1,11 @@
+
+
+int foo_value = 1;
+
+void __attribute__((constructor)) setup_foo()
+{
+       foo_value = 2;
+}
+
+
+
diff --git a/unit-tests/test-cases/image-state-dependents-initialized/main.c b/unit-tests/test-cases/image-state-dependents-initialized/main.c
new file mode 100644 (file)
index 0000000..d4933f8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main(int argc, const char* argv[])
+{      
+       PASS("image-state-dependents-initialized");
+               
+       return EXIT_SUCCESS;
+}
+
+
+int main_value = 1;
+
+void __attribute__((constructor)) setup_main()
+{
+       main_value = 2;
+}
+
index 3c39e9863bafd182dbb5aa264f2b9ef83d0b7d47..43172041f3dbb9f6abf02761e38b225a3c238594 100644 (file)
@@ -28,7 +28,7 @@ run :  check1 check2 check3 check4 check5 check6 check7 check8
 all :  main1 main2 main3 main4 main5 main6 main7 main8  
 
 main : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main 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
@@ -68,7 +68,7 @@ clean:
 #   (fails on 10.3)
 #
 main1 : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main1 libfoo.dylib
+       ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main1 libfoo.dylib
 
 check1:        main1
        DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 libfoo.dylib
@@ -79,7 +79,7 @@ check1:       main1
 # check2: main links with libfoo_debug.dylib and dynamically loads libfoo.dylib
 #
 main2 : main.c libfoo_debug.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main2 libfoo_debug.dylib
+       ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main2 libfoo_debug.dylib
 
 check2:        main2
        echo "pwd-1 is ${PWD}"
@@ -92,7 +92,7 @@ check2:       main2
 # check3: main links with libfoo.dylib sets DYLD_LIBRARY_PATH=hide and dynamically loads libfoo.dylib
 #
 main3 : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main3 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
@@ -103,7 +103,7 @@ check3:     main3
 #   (fails on 10.3)
 #
 main4 : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main4 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
@@ -114,7 +114,7 @@ check4:     main4
 #   (fails on 10.3)
 #
 main5 : main.c libbar.dylib libbar_debug.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main5 libbar.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
@@ -125,7 +125,7 @@ check5:     main5
 #   (fails on 10.3)
 #
 main6 : main.c libbar_debug.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main6 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
@@ -135,7 +135,7 @@ check6:     main6
 # check7: main links with libbar.dylib sets DYLD_LIBRARY_PATH=hide and dynamically loads libbar.dylib
 #
 main7 : main.c libbar.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main7 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
@@ -146,7 +146,7 @@ check7:     main7
 #   (fails on 10.3)
 #
 main8 : main.c libbar.dylib
-       ${CC} -I${TESTROOT}/include  main.c -o main8 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
index 3b5e6be8689337e5973d023601dd30033012196a..1afdb745fcdfc68154b13a014987619c7ebe958a 100644 (file)
@@ -27,7 +27,7 @@ run: all
        ./main arg1 arg2
 
 all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c
 
 clean:
        ${RM} ${RMFLAGS} *~ main
index 352ec10dd2f532321ae0dbff0e1a3755d4608ff3..f4ae30ace4523fd3cad2194039a4dd5d537d5221 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+#
+# verifies that initializers for inserted libraries run before the
+# main executables initializers
+#
+
+
 run: all
-       export DYLD_INSERT_LIBRARIES="libfoo.dylib" && ./main
+       export DYLD_INSERT_LIBRARIES=libinsert.dylib && ./main
 
-all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+all: main libinsert.dylib
+
+
+main: main.c libfoo1.dylib libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c  libfoo1.dylib  libbase.dylib
 
-clean:
-       ${RM} ${RMFLAGS} *~ main libfoo.dylib
 
+libfoo1.dylib: foo1.c libbase.dylib libfoo2.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib  -o libfoo1.dylib  foo1.c  libbase.dylib libfoo2.dylib
+
+libfoo2.dylib: foo2.c libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib  -o libfoo2.dylib  foo2.c  libbase.dylib
+
+libinsert.dylib: insert.c libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib  -o libinsert.dylib  insert.c  libbase.dylib
+
+libbase.dylib: base.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib  -o libbase.dylib  base.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  lib*.dylib
+       
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/base.c b/unit-tests/test-cases/insert-libraries-with-initializer/base.c
new file mode 100644 (file)
index 0000000..fcd63c6
--- /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@
+ */
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "base.h"
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static int state = 1;
+bool badOrder = false;
+
+void setState(int nextState)
+{
+       if ( nextState == state )
+               ++state;
+       else
+               badOrder = true;
+
+}
+
+
+void baseCheck()
+{
+       if ( badOrder ) 
+               FAIL("insert-libraries-with-initializers bad state at %d", state);
+       else
+               PASS("insert-libraries-with-initializers");
+}
+
+
+
+
+
+
+static __attribute__((constructor)) void base_init() 
+{
+       //fprintf(stderr, "base_init()\n");
+       setState(1);
+}
+
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/base.h b/unit-tests/test-cases/insert-libraries-with-initializer/base.h
new file mode 100644 (file)
index 0000000..1dbf697
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+extern void setState(int);
+extern void baseCheck();
+
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/foo.c b/unit-tests/test-cases/insert-libraries-with-initializer/foo.c
deleted file mode 100644 (file)
index 60a2d84..0000000
+++ /dev/null
@@ -1,35 +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@
- */
-#include <stdlib.h>
-
-#include "test.h"
-
-static
-void
-__attribute__((constructor))
-my_init()
-{
-  PASS("initializer/constructor was called");
-  exit(EXIT_SUCCESS);
-}
-
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/foo1.c b/unit-tests/test-cases/insert-libraries-with-initializer/foo1.c
new file mode 100644 (file)
index 0000000..ac55290
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 "base.h"
+
+
+
+
+// should run fourth because first initiallzer in second .o file
+static __attribute__((constructor)) void foo1_init() 
+{
+       //fprintf(stderr, "foo1_init()\n");
+       setState(4);
+}
+
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/foo2.c b/unit-tests/test-cases/insert-libraries-with-initializer/foo2.c
new file mode 100644 (file)
index 0000000..6574e02
--- /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 "base.h"
+
+
+// should run fourth because first initiallzer in second .o file
+static __attribute__((constructor)) void foo2_init() 
+{
+       //fprintf(stderr, "foo2_init()\n");
+       setState(3);
+}
+
diff --git a/unit-tests/test-cases/insert-libraries-with-initializer/insert.c b/unit-tests/test-cases/insert-libraries-with-initializer/insert.c
new file mode 100644 (file)
index 0000000..79d78a2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 "base.h"
+
+
+
+
+static __attribute__((constructor)) void insert() 
+{
+       //fprintf(stderr, "insert()\n");
+       setState(2);
+}
+
index bb193e75ac540c2952941b456f527ee5aa66b3a1..64df39739e1027ce78dfabc426da02e41dd2de81 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
-int
-main(int argc, char **argv, char **envp, char**appl)
+
+#include "base.h"
+
+int main()
 {
-  FAIL("initializer/constructor was not called");
-  return EXIT_SUCCESS;
+       baseCheck();
+       return EXIT_SUCCESS;
 }
+
+
+static __attribute__((constructor)) void main_init() 
+{
+       //fprintf(stderr, "main_init()\n");
+       setState(5);
+}
+
index f3037cdb6ad2c21725cd65de4398eb913be564c4..558fc57d0d082c9c99aacf17ede7fb4eb7315e6e 100644 (file)
@@ -25,13 +25,13 @@ include ${TESTROOT}/include/common.makefile
 
 MACHINE =  $(shell machine)
 
-ifeq "-arch ppc" "$(ARCH)"
+ifeq "ppc" "$(ARCH)"
        EXTRA_FLAG = -maltivec -force_cpusubtype_ALL
 else 
-       ifeq "-arch ppc64" "$(ARCH)"
+       ifeq "ppc64" "$(ARCH)"
                EXTRA_FLAG = -maltivec
        else
-               ifeq "-arch i386" "$(ARCH)"
+               ifeq "i386" "$(ARCH)"
                        EXTRA_FLAG = ""
                else
                        ifeq "" "$(ARCH)"
index 00727805ccb611dce8fe04cd8f6237bdad668442..007f11de7a670fa5438893b2683e47cdb3854358 100644 (file)
@@ -15,7 +15,7 @@ extern bool dofloattest(double,double,double,double,double,double,double,double,
 #if __i386__ || __x86_64__
        typedef float               vFloat  __attribute__ ((__vector_size__ (16)));
 #elif __ppc__ || __ppc64__
-       typedef vector float            vFloat;
+       typedef __vector float          vFloat;
 #endif
 
 extern bool dovectortest(vFloat, vFloat, vFloat, vFloat, vFloat);
index 6b342078eadf1f924a0158afe9b049a90e9cfaf9..694cd9d678b99cc85f971576ad5b519e2c7ed996 100644 (file)
@@ -44,7 +44,7 @@ libfoo2.dylib : foo.c
 
 
 main : main.c libfoo2.dylib hide/libbar.dylib hide/libfoo3.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main hide/libbar.dylib libfoo2.dylib 
+       ${CC}   -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main hide/libbar.dylib libfoo2.dylib 
        install_name_tool -change libfoo2.dylib '@loader_path/libfoo2.dylib'      main
        install_name_tool -change libbar.dylib  '@loader_path/hide/libbar.dylib'  main
 
index 46698adb24633e0e46eb7d71e8f7f144a431fdc8..a2233c801cff18d6cf6dab8ba858e4340b6ab4a8 100644 (file)
@@ -26,7 +26,7 @@
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 int
-main(int argc, char **argv, char **envp, char**appl)
+main(int argc, const char* argv[])
 {
   
   return EXIT_SUCCESS;
diff --git a/unit-tests/test-cases/operator-new/Makefile b/unit-tests/test-cases/operator-new/Makefile
new file mode 100644 (file)
index 0000000..fb7fe84
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+run: all
+       ./main
+
+all: main
+
+
+main: main.cxx
+       ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  
+
diff --git a/unit-tests/test-cases/operator-new/main.cxx b/unit-tests/test-cases/operator-new/main.cxx
new file mode 100644 (file)
index 0000000..ead5c1e
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include <stdlib.h>
+#include <new>
+
+//
+// This test case verifies that calling operator new[] in libstdc++.dylib
+// will turn around and call operator new in this main exectuable
+//
+
+static void* ptr;
+
+void* operator new(size_t s) throw (std::bad_alloc)
+{
+  ptr = malloc(s);
+  return ptr;
+}
+
+
+int main()
+{
+       char* stuff = new char[24];
+       if ( (void*)stuff == ptr )
+               PASS("operator-new");
+       else
+               FAIL("operator-new");
+       return EXIT_SUCCESS;
+}
+
+
+// add this so WEAK_DEFINES is set, so dyld searchs this image
+int __attribute__((weak)) junk = 2;
index 2cff5196f15f51d92562db8a2d89dccfd2b2654f..37a84a45563d581a97944f53d4ff189f14360091 100644 (file)
@@ -38,7 +38,7 @@ run: all
 all: main test.bundle
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
 
 test.bundle : bundle.c libfoo.dylib
        ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c libfoo.dylib
diff --git a/unit-tests/test-cases/pie-basic/Makefile b/unit-tests/test-cases/pie-basic/Makefile
new file mode 100644 (file)
index 0000000..2a2f680
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# run a PIE four times and verify its load address was different every time
+
+
+run: main
+       ./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; \
+        
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main.out
+
diff --git a/unit-tests/test-cases/pie-basic/main.c b/unit-tests/test-cases/pie-basic/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;
+}
diff --git a/unit-tests/test-cases/pie-big/Makefile b/unit-tests/test-cases/pie-big/Makefile
new file mode 100644 (file)
index 0000000..6d4d95b
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# run a PIE four times and verify its load address was different every time
+
+
+run: main
+       ./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 "XFAIL pie-basic"; \
+       fi; \
+        
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main.out
+
diff --git a/unit-tests/test-cases/pie-big/main.c b/unit-tests/test-cases/pie-big/main.c
new file mode 100644 (file)
index 0000000..f7e3b88
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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>
+
+char bigarray[1500000000];
+
+
+int main()
+{
+       //int local;
+       
+       printf("&main=%p\n", &main);
+       //printf("&local=%p\n",&local);
+       return 0;
+}
diff --git a/unit-tests/test-cases/pie-custom-stack/Makefile b/unit-tests/test-cases/pie-custom-stack/Makefile
new file mode 100644 (file)
index 0000000..48ff01e
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# run a PIE four times and verify its load address was different every time
+
+
+run: main
+       ./main > main.out
+       ./main >> main.out
+       ./main >> main.out
+       ./main >> main.out
+       if [ `sort main.out -u | wc -l` == 4 ]; \
+       then \
+               echo "PASS pie-custom-stack"; \
+       else \
+               echo "FAIL pie-custom-stack"; \
+       fi; \
+        
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5 -Wl,-stack_size,0x10000000
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main.out
+
diff --git a/unit-tests/test-cases/pie-custom-stack/main.c b/unit-tests/test-cases/pie-custom-stack/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 f895d900b2f70d522aedfa322a92dfce6e018a21..b469f9f87d545eaceb335d6dd2b68c07a8f67711 100644 (file)
@@ -25,10 +25,10 @@ include ${TESTROOT}/include/common.makefile
 
 DYLIB_BASES_ADDRESS = 0x10000000
 
-ifeq "-arch ppc64" "$(ARCH)"
+ifeq "ppc64" "$(ARCH)"
        DYLIB_BASES_ADDRESS = 0x300000000
 else 
-       ifeq "-arch x86_64" "$(ARCH)"
+       ifeq "x86_64" "$(ARCH)"
                DYLIB_BASES_ADDRESS = 0x300000000
        endif
 endif
index 0da036f208818af2f537026c79854c493e6f1fab..1836973e174608590cf8b782ca863817296d14ea 100644 (file)
@@ -66,6 +66,8 @@ bool checkRebasing()
                        ++dirtyPageCount;
        }
 
+       //fprintf(stderr, "dirtyPageCount=%d\n", dirtyPageCount);
+
        // if there are too many dirty pages, then dyld is inefficient
        return ( dirtyPageCount < 2 );
 }
diff --git a/unit-tests/test-cases/progname/Makefile b/unit-tests/test-cases/progname/Makefile
new file mode 100644 (file)
index 0000000..b0ee016
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# 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
+
+run: all
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/progname/main.c b/unit-tests/test-cases/progname/main.c
new file mode 100644 (file)
index 0000000..1f05111
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static const char* name = NULL;
+
+
+static void checker() __attribute__((constructor));
+static void checker()
+{
+       name = strdup(getprogname());
+}
+
+
+
+int
+main(int argc, const char* argv[])
+{
+       // verify that getprogname() works during initializers
+       if ( strcmp(name, getprogname()) == 0 )
+               PASS("progname");
+       else
+               FAIL("progname");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/re-export-dylib/Makefile b/unit-tests/test-cases/re-export-dylib/Makefile
new file mode 100644 (file)
index 0000000..cb28183
--- /dev/null
@@ -0,0 +1,62 @@
+##
+# 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
+
+PWD = `pwd`
+
+
+#
+# Test that the 10.4 and 10.5 ways to re-export a dylib work
+#
+
+run : all
+       ./main4
+       ./main5
+
+all : main4 main5
+
+libbar4.dylib : bar.c
+       gcc 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
+
+main4 : main.c libfoo4.dylib
+       gcc 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
+
+libfoo5.dylib : foo.c libbar5.dylib
+       gcc foo.c -dynamiclib libbar5.dylib -sub_library libbar5 -o $(PWD)/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
+
+       
+clean:
+       rm -rf main4 main5 libfoo4.dylib libfoo5.dylib libbar4.dylib libbar5.dylib
+       
\ No newline at end of file
diff --git a/unit-tests/test-cases/re-export-dylib/bar.c b/unit-tests/test-cases/re-export-dylib/bar.c
new file mode 100644 (file)
index 0000000..b0faf2f
--- /dev/null
@@ -0,0 +1,6 @@
+int bar()
+{
+       return 1;
+}
+
+
diff --git a/unit-tests/test-cases/re-export-dylib/foo.c b/unit-tests/test-cases/re-export-dylib/foo.c
new file mode 100644 (file)
index 0000000..2486c7a
--- /dev/null
@@ -0,0 +1,5 @@
+int foo()
+{
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/re-export-dylib/main.c b/unit-tests/test-cases/re-export-dylib/main.c
new file mode 100644 (file)
index 0000000..2d54c74
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <mach-o/dyld.h>
+
+#include "test.h"
+
+
+
+extern int foo();
+extern int bar();
+
+int main()
+{
+       foo();
+       bar();
+       PASS("re-export-dylib");
+       return 0;
+}
diff --git a/unit-tests/test-cases/re-export-framework/Makefile b/unit-tests/test-cases/re-export-framework/Makefile
new file mode 100644 (file)
index 0000000..b474053
--- /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
+
+PWD = `pwd`
+
+
+#
+# Test that the 10.4 and 10.5 ways to re-export a framework work
+#
+
+run : 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
+
+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
+
+main4 : main.c Foo4.framework/Foo4
+       gcc 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
+
+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
+
+main5 : main.c Foo5.framework/Foo5
+       gcc main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+
+
+
+       
+clean:
+       rm -rf main4 Foo4.framework Bar4.framework main5 Foo5.framework Bar5.framework 
+       
\ No newline at end of file
diff --git a/unit-tests/test-cases/re-export-framework/bar.c b/unit-tests/test-cases/re-export-framework/bar.c
new file mode 100644 (file)
index 0000000..b0faf2f
--- /dev/null
@@ -0,0 +1,6 @@
+int bar()
+{
+       return 1;
+}
+
+
diff --git a/unit-tests/test-cases/re-export-framework/foo.c b/unit-tests/test-cases/re-export-framework/foo.c
new file mode 100644 (file)
index 0000000..2486c7a
--- /dev/null
@@ -0,0 +1,5 @@
+int foo()
+{
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/re-export-framework/main.c b/unit-tests/test-cases/re-export-framework/main.c
new file mode 100644 (file)
index 0000000..7ad3fed
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <mach-o/dyld.h>
+
+#include "test.h"
+
+
+
+extern int foo();
+extern int bar();
+
+int main()
+{
+       foo();
+       bar();
+       PASS("re-export-framework");
+       return 0;
+}
diff --git a/unit-tests/test-cases/re-export-sub-framework/Makefile b/unit-tests/test-cases/re-export-sub-framework/Makefile
new file mode 100644 (file)
index 0000000..1b761f5
--- /dev/null
@@ -0,0 +1,66 @@
+##
+# 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
+
+PWD = `pwd`
+
+
+#
+# Test that the 10.4 and 10.5 ways to re-export a sub framework work
+#
+
+run : 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
+
+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
+
+main4 : main.c Foo4.framework/Foo4
+       gcc 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
+
+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
+
+main5 : main.c Foo5.framework/Foo5
+       gcc main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+
+
+       
+clean:
+       rm -rf main4 Foo4.framework Bar4.framework main5 Foo5.framework Bar5.framework 
+       
\ No newline at end of file
diff --git a/unit-tests/test-cases/re-export-sub-framework/bar.c b/unit-tests/test-cases/re-export-sub-framework/bar.c
new file mode 100644 (file)
index 0000000..b0faf2f
--- /dev/null
@@ -0,0 +1,6 @@
+int bar()
+{
+       return 1;
+}
+
+
diff --git a/unit-tests/test-cases/re-export-sub-framework/foo.c b/unit-tests/test-cases/re-export-sub-framework/foo.c
new file mode 100644 (file)
index 0000000..2486c7a
--- /dev/null
@@ -0,0 +1,5 @@
+int foo()
+{
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/re-export-sub-framework/main.c b/unit-tests/test-cases/re-export-sub-framework/main.c
new file mode 100644 (file)
index 0000000..fe2ae5e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <mach-o/dyld.h>
+
+#include "test.h"
+
+
+
+extern int foo();
+extern int bar();
+
+int main()
+{
+       foo();
+       bar();
+       PASS("re-export-sub-framework");
+       return 0;
+}
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-coalesce/Makefile b/unit-tests/test-cases/read-only-import-shared-cache-coalesce/Makefile
new file mode 100644 (file)
index 0000000..efd6319
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2006-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
+
+
+run: all
+       ./main
+
+all: main
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS}  -o main main.c
+
+libfoo.dylib: foo.cxx
+       ${CXX} ${CXXFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.cxx
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib
+       
+
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-coalesce/foo.cxx b/unit-tests/test-cases/read-only-import-shared-cache-coalesce/foo.cxx
new file mode 100644 (file)
index 0000000..9bf26a8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2006-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()
+
+#include <stdlib.h>
+#include <new>
+
+//
+// This test case verifies that calling operator new[] in libstdc++.dylib
+// will turn around and call operator new in this main exectuable
+//
+
+static void* ptr;
+
+void* operator new(size_t s) throw (std::bad_alloc)
+{
+  ptr = malloc(s);
+  return ptr;
+}
+
+
+int check()
+{
+       char* stuff = new char[24];
+       if ( (void*)stuff == ptr )
+               PASS("operator-new");
+       else
+               FAIL("operator-new");
+       return 0;
+}
+
+int x = check(); // runs when library is loaded
+
+// add this so WEAK_DEFINES is set, so dyld searchs this image
+int __attribute__((weak)) junk = 2;
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-coalesce/main.c b/unit-tests/test-cases/read-only-import-shared-cache-coalesce/main.c
new file mode 100644 (file)
index 0000000..4579fe4
--- /dev/null
@@ -0,0 +1,12 @@
+
+#include <dlfcn.h>
+
+int main()
+{
+       // dynamically load libfoo.dylib which depends on libstdc++.dylib 
+       // being re-bound to libfoo's operator new.
+       dlopen("libfoo.dylib", RTLD_LAZY);
+       return 0;
+}      
+
+
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/Makefile b/unit-tests/test-cases/read-only-import-shared-cache-override/Makefile
new file mode 100644 (file)
index 0000000..c8b9346
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+run: all
+       export DYLD_LIBRARY_PATH=`pwd` && ./main
+
+all: main libSystem.B.dylib
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS}  -o main main.c
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.c -framework Cocoa
+
+libSystem.B.dylib: /usr/lib/libSystem.B.dylib
+       cp /usr/lib/libSystem.B.dylib ./libSystem.B.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libSystem.B.dylib libfoo.dylib 
+       
+
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/foo.c b/unit-tests/test-cases/read-only-import-shared-cache-override/foo.c
new file mode 100644 (file)
index 0000000..322485e
--- /dev/null
@@ -0,0 +1,18 @@
+
+#include <strings.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "test.h"
+
+void __attribute__((constructor)) init()
+{
+       uintptr_t libSysFuncAddr = (uintptr_t)&strcmp;
+       uintptr_t cfFuncAddr     = (uintptr_t)&CFStringGetTypeID;
+       if ( cfFuncAddr - libSysFuncAddr < 256*1024*1024 )
+               PASS("read-only-import-shared-cache-override");
+       else
+               PASS("read-only-import-shared-cache-override");
+}      
+
+
+
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/main.c b/unit-tests/test-cases/read-only-import-shared-cache-override/main.c
new file mode 100644 (file)
index 0000000..cc404ed
--- /dev/null
@@ -0,0 +1,10 @@
+#include <dlfcn.h>
+
+int main()
+{
+       // dynamically load libfoo.dylib which depends on libstdc++.dylib 
+       // being re-bound to libfoo's operator new.
+       dlopen("libfoo.dylib", RTLD_LAZY);
+       return 0;
+}      
+
diff --git a/unit-tests/test-cases/read-only-stubs/Makefile b/unit-tests/test-cases/read-only-stubs/Makefile
new file mode 100644 (file)
index 0000000..d3a63ab
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main
+
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -Wl,-read_only_stubs -I${TESTROOT}/include main.c libfoo.dylib -o main 
+
+libfoo.dylib: foo.c libbar.dylib
+       ${CC} ${CCFLAGS} -Wl,-read_only_stubs -I${TESTROOT}/include -dynamiclib foo.c  libbar.dylib -o libfoo.dylib  
+
+libbar.dylib: bar.c 
+       ${CC} ${CCFLAGS} -Wl,-read_only_stubs -I${TESTROOT}/include -dynamiclib bar.c  -o libbar.dylib  
+
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib libbar.dylib
+       
diff --git a/unit-tests/test-cases/read-only-stubs/bar.c b/unit-tests/test-cases/read-only-stubs/bar.c
new file mode 100644 (file)
index 0000000..d9a1c20
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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()
+
+
+int barData = 1;
+
+void bar()
+{
+}
+
+
diff --git a/unit-tests/test-cases/read-only-stubs/foo.c b/unit-tests/test-cases/read-only-stubs/foo.c
new file mode 100644 (file)
index 0000000..01fc9a8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <unistd.h>
+#include <mach-o/getsect.h>
+#include <mach-o/ldsyms.h>
+#include <mach/mach.h> 
+#include <mach/mach_vm.h> 
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern void bar();
+extern int barData;
+
+
+static vm_prot_t getPermission(void* addr)
+{
+    mach_vm_address_t                          address = (mach_vm_address_t)(uintptr_t)addr;
+    kern_return_t                                      result;
+    mach_port_t                                                object_name;
+    vm_region_basic_info_data_64_t     info;
+    mach_msg_type_number_t                     count;
+    mach_vm_size_t                                     size = 4096;
+       
+       count = VM_REGION_BASIC_INFO_COUNT_64;
+       result = mach_vm_region(mach_task_self(),
+                                       &address,
+                                       &size,
+                                       VM_REGION_BASIC_INFO_64,
+                                       (vm_region_info_t)&info,
+                                       &count,
+                                       &object_name);   
+       if ( result == KERN_SUCCESS ) 
+               return info.protection;
+       return 0;
+}
+
+
+static void* getStubAddr()
+{
+#if __LP64__
+       uint64_t size;
+#else
+       uint32_t size;
+#endif
+       uintptr_t slide = (uintptr_t)&_mh_dylib_header; // assume dylib is zero-base so slide == load address
+#if __i386__
+       return getsectdatafromheader(&_mh_dylib_header, "__IMPORT", "__jump_table", &size) + slide;
+#elif __ppc__
+       return getsectdatafromheader(&_mh_dylib_header, "TEXT", "__picsymbolstub1", &size) + slide;
+#elif __ppc64__
+       return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__picsymbolstub1", &size) + slide;
+#elif __x86_64__
+       return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__symbol_stub1", &size) + slide;
+#else
+       #error unknown arch
+#endif
+}
+
+
+static void checkStubs(void* addr)
+{
+       vm_prot_t perm = getPermission(addr);
+       if ( (perm == 0) || ((perm & VM_PROT_WRITE) != 0) ) {
+               FAIL("read-only-stubs: bad permissions %d at address %p", perm, addr);
+               exit(0);
+       }
+}
+
+int fooData = 1;
+
+void foo()
+{
+       void* stubAddr = getStubAddr(); 
+       checkStubs(stubAddr);
+       barData = 0;
+       bar();
+       checkStubs(stubAddr);
+}
+
+
diff --git a/unit-tests/test-cases/read-only-stubs/main.c b/unit-tests/test-cases/read-only-stubs/main.c
new file mode 100644 (file)
index 0000000..3c3dca9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <unistd.h>
+#include <mach-o/getsect.h>
+#include <mach/mach.h> 
+#include <mach/mach_vm.h> 
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern void foo();
+extern int fooData;
+
+static vm_prot_t getPermission(void* addr)
+{
+    mach_vm_address_t                          address = (mach_vm_address_t)(uintptr_t)addr;
+    kern_return_t                                      result;
+    mach_port_t                                                object_name;
+    vm_region_basic_info_data_64_t     info;
+    mach_msg_type_number_t                     count;
+    mach_vm_size_t                                     size = 4096;
+       
+       count = VM_REGION_BASIC_INFO_COUNT_64;
+       result = mach_vm_region(mach_task_self(),
+                                       &address,
+                                       &size,
+                                       VM_REGION_BASIC_INFO_64,
+                                       (vm_region_info_t)&info,
+                                       &count,
+                                       &object_name);       
+       //fprintf(stderr, "result=%X, info.protection=%X\n", result, info.protection);
+       if ( result == KERN_SUCCESS ) 
+               return info.protection;
+       return 0;
+}
+
+
+static void* getStubAddr()
+{
+       unsigned long size;
+#if __i386__
+       return getsectdata("__IMPORT", "__jump_table", &size);
+#elif __ppc__
+       void* p = getsectdata("__TEXT", "__picsymbolstub1", &size);
+       if ( p != NULL ) 
+               return p;
+       return getsectdata("__TEXT", "__symbol_stub1", &size);
+#elif __ppc64__
+       return getsectdata("__TEXT", "__picsymbolstub1", &size);
+#elif __x86_64__
+       return getsectdata("__TEXT", "__symbol_stub1", &size);
+#else
+       #error unknown arch
+#endif
+}
+
+
+static void checkStubs(void* addr)
+{
+       vm_prot_t perm = getPermission(addr);
+       if ( (perm == 0) || ((perm & VM_PROT_WRITE) != 0) ) {
+               FAIL("read-only-stubs: bad permissions %d at address %p", perm, addr);
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       void* stubAddr = getStubAddr(); 
+       checkStubs(stubAddr);
+       fooData = 1;
+       foo();
+       checkStubs(stubAddr);
+       PASS("read-only-stubs");
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/Makefile b/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..a011834
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# 1) a main executable built with -rpath run with DYLD_FALLBACK_LIBRARY_PATH and linked rpath wins
+# 2) a main executable built without -rpath run with DYLD_FALLBACK_LIBRARY_PATH and dylib found
+#
+
+
+run: all
+       export DYLD_FALLBACK_LIBRARY_PATH=`pwd`/bad && ./main
+       export DYLD_FALLBACK_LIBRARY_PATH=`pwd`/good && ./main2
+
+all: main main2 bad/libfoo.dylib
+
+       
+good/libfoo.dylib : foo.c
+       mkdir -p good
+       ${CC} foo.c -dynamiclib -o good/libfoo.dylib -install_name @rpath/libfoo.dylib
+       
+bad/libfoo.dylib : foo.c
+       mkdir -p bad
+       ${CC} foo.c -DBAD -dynamiclib -o bad/libfoo.dylib -install_name @rpath/libfoo.dylib
+
+main : main.c good/libfoo.dylib 
+       ${CC} -I${TESTROOT}/include main.c -o main good/libfoo.dylib -Wl,-rpath -Wl,@loader_path/good
+
+main2 : main.c good/libfoo.dylib 
+       ${CC} -I${TESTROOT}/include main.c -o main2 good/libfoo.dylib 
+
+clean:
+       ${RM} ${RMFLAGS} *~  main main2 good bad
diff --git a/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/foo.c b/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/foo.c
new file mode 100644 (file)
index 0000000..a8fe5b0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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@
+ */
+int foo()
+{
+#if BAD
+       return 0;
+#else
+       return 1;
+#endif
+}
diff --git a/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/main.c b/unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..72afbf7
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern int foo();
+
+int main()
+{
+       if ( foo() )
+               PASS("rpath-DYLD_FALLBACK_LIBRARY_PATH");
+       else
+               FAIL("rpath-DYLD_FALLBACK_LIBRARY_PATH");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/Makefile b/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..153f718
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable run with DYLD_LIBRARY_PATH will override its rpath
+#
+
+
+run: all
+       export DYLD_LIBRARY_PATH=`pwd`/hide1 && ./main
+
+all: main hide2/libfoo.dylib hide1/libfoo.dylib
+
+       
+hide1/libfoo.dylib : foo.c
+       mkdir -p hide1
+       ${CC} foo.c -dynamiclib -o hide1/libfoo.dylib -install_name @rpath/libfoo.dylib
+       
+hide2/libfoo.dylib : foo.c
+       mkdir -p hide2
+       ${CC} foo.c -DBAD -dynamiclib -o hide2/libfoo.dylib -install_name @rpath/libfoo.dylib
+
+main : main.c hide2/libfoo.dylib 
+       ${CC} -I${TESTROOT}/include main.c -o main hide2/libfoo.dylib -Wl,-rpath -Wl,@loader_path/hide2
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide1 hide2
diff --git a/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/foo.c b/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/foo.c
new file mode 100644 (file)
index 0000000..a8fe5b0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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@
+ */
+int foo()
+{
+#if BAD
+       return 0;
+#else
+       return 1;
+#endif
+}
diff --git a/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/main.c b/unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..01a144b
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern int foo();
+
+int main()
+{
+       if ( foo() )
+               PASS("rpath-DYLD_LIBRARY_PATH");
+       else
+               FAIL("rpath-DYLD_LIBRARY_PATH");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/Makefile b/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..ba5400d
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable run with LD_LIBRARY_PATH can locate a dylib it links against
+#
+
+
+run: all
+       export LD_LIBRARY_PATH=`pwd`/hide/hole && ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${CC} foo.c -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
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide
diff --git a/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/foo.c b/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/main.c b/unit-tests/test-cases/rpath-LD_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..784dee3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       PASS("rpath-LD_LIBRARY_PATH");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-basic/Makefile b/unit-tests/test-cases/rpath-basic/Makefile
new file mode 100644 (file)
index 0000000..536d651
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable linked with -rpath used to locate a dylib it links against
+#
+
+
+run: all
+       ./main
+
+all: main
+
+       
+hide/hole/libbar.dylib : bar.c
+       mkdir -p hide/hole
+       ${CC} bar.c -dynamiclib -o hide/hole/libbar.dylib -install_name @rpath/libbar.dylib
+
+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
+
+clean:
+       ${RM} -rf *~  main hide
diff --git a/unit-tests/test-cases/rpath-basic/bar.c b/unit-tests/test-cases/rpath-basic/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/rpath-basic/foo.c b/unit-tests/test-cases/rpath-basic/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/rpath-basic/main.c b/unit-tests/test-cases/rpath-basic/main.c
new file mode 100644 (file)
index 0000000..bf6c7fa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       PASS("rpath-basic");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-in-dylib/Makefile b/unit-tests/test-cases/rpath-dlopen-in-dylib/Makefile
new file mode 100644 (file)
index 0000000..d94f47d
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# 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
+
+
+#
+# a main executable linked with -rpath calls into a dylib which calls 
+# dlopen().  The -rpath from the dylib should be used to
+# find the dlopen path.
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${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
+
+main : main.c libbar.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main libbar.dylib
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide libbar.dylib
diff --git a/unit-tests/test-cases/rpath-dlopen-in-dylib/bar.c b/unit-tests/test-cases/rpath-dlopen-in-dylib/bar.c
new file mode 100644 (file)
index 0000000..17ab4f6
--- /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 "test.h"
+
+void bar()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("rpath-dlopen-indirect: %s", dlerror());
+               exit(EXIT_SUCCESS);
+       }
+       
+       void* pFoo = dlsym(handle, "foo");
+       if ( pFoo == NULL ) {
+               FAIL("rpath-dlopen-indirect: %s", dlerror());
+               exit(EXIT_SUCCESS);
+       }
+}
+
+
diff --git a/unit-tests/test-cases/rpath-dlopen-in-dylib/foo.c b/unit-tests/test-cases/rpath-dlopen-in-dylib/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/rpath-dlopen-in-dylib/main.c b/unit-tests/test-cases/rpath-dlopen-in-dylib/main.c
new file mode 100644 (file)
index 0000000..1eb7429
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 "test.h"
+
+extern void bar();
+
+int main()
+{
+       bar();
+       
+       PASS("rpath-dlopen-in-dylib");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-indirect/Makefile b/unit-tests/test-cases/rpath-dlopen-indirect/Makefile
new file mode 100644 (file)
index 0000000..b679f77
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable linked with -rpath calls into a dylib which calls 
+# dlopen().  The -rpath from the main executable should be used to
+# find the dlopen path.
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${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
+
+main : main.c libbar.dylib
+       ${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
diff --git a/unit-tests/test-cases/rpath-dlopen-indirect/bar.c b/unit-tests/test-cases/rpath-dlopen-indirect/bar.c
new file mode 100644 (file)
index 0000000..160109b
--- /dev/null
@@ -0,0 +1,23 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+void bar()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("rpath-dlopen-indirect: %s", dlerror());
+               exit(EXIT_SUCCESS);
+       }
+       
+       void* pFoo = dlsym(handle, "foo");
+       if ( pFoo == NULL ) {
+               FAIL("rpath-dlopen-indirect: %s", dlerror());
+               exit(EXIT_SUCCESS);
+       }
+}
+
+
diff --git a/unit-tests/test-cases/rpath-dlopen-indirect/foo.c b/unit-tests/test-cases/rpath-dlopen-indirect/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-indirect/main.c b/unit-tests/test-cases/rpath-dlopen-indirect/main.c
new file mode 100644 (file)
index 0000000..ba7efb6
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+extern void bar();
+
+int main()
+{
+       bar();
+       
+       PASS("rpath-dlopen-indirect");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-leak/Makefile b/unit-tests/test-cases/rpath-dlopen-leak/Makefile
new file mode 100644 (file)
index 0000000..2261028
--- /dev/null
@@ -0,0 +1,64 @@
+##
+# 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 using @loader_path based rpaths
+#
+
+# leaks does not work on rosetta processes
+EMULATED = 0
+ifeq "ppc" "$(ARCH)"
+       MACHINE =  $(shell arch)
+       ifeq "i386" "$(MACHINE)"
+               EMULATED = 1
+       endif
+endif
+
+
+run: all
+       if [ ${EMULATED} == 0 ]; \
+       then \
+               ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-leak" "rpath-dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"; \
+               ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-leak" "rpath-dlopen-leak" "./main.bad | grep '0 leaks for 0 total leaked bytes' > /dev/null"; \
+       else \
+               echo "XFAIL rpath-dlopen-leak"; \
+       fi;
+       
+all: main main.bad
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${CC} foo.c -dynamiclib -o hide/hole/libfoo.dylib -install_name @rpath/libfoo.dylib
+       
+
+main : main.c hide/hole/libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main -Wl,-rpath -Wl,@loader_path/hide/hole
+
+main.bad : main.c hide/hole/libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main.bad -Wl,-rpath -Wl,@loader_path/bad
+
+clean:
+       ${RM} ${RMFLAGS} *~  main main.bad hide/hole/libfoo.dylib hide
diff --git a/unit-tests/test-cases/rpath-dlopen-leak/foo.c b/unit-tests/test-cases/rpath-dlopen-leak/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-leak/main.c b/unit-tests/test-cases/rpath-dlopen-leak/main.c
new file mode 100644 (file)
index 0000000..b33ceca
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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);
+       }
+       
+       // 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/rpath-dlopen/Makefile b/unit-tests/test-cases/rpath-dlopen/Makefile
new file mode 100644 (file)
index 0000000..ce34746
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable linked with -rpath and uses dlopen can find a dylib
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${CC} foo.c -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 -Wl,-rpath -Wl,`pwd`/hide/hole
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide
diff --git a/unit-tests/test-cases/rpath-dlopen/foo.c b/unit-tests/test-cases/rpath-dlopen/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-dlopen/main.c b/unit-tests/test-cases/rpath-dlopen/main.c
new file mode 100644 (file)
index 0000000..d413906
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+
+int main()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("rpath-dlopen: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       void* pFoo = dlsym(handle, "foo");
+       if ( pFoo == NULL ) {
+               FAIL("rpath-dlopen: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       PASS("rpath-dlopen");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-executable_path/Makefile b/unit-tests/test-cases/rpath-executable_path/Makefile
new file mode 100644 (file)
index 0000000..76dde9f
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2006-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
+
+
+#
+# a main executable linked with -rpath that uses @executable_path.
+# The @executable_path in the rpath should expand at runtime to the directory
+# of the main executable.
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${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 hide/hole/libfoo.dylib
+
+main : main.c libbar.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main libbar.dylib -Wl,-rpath -Wl,@executable_path/hide/hole
+
+clean:
+       ${RM} -rf *~  main hide libbar.dylib
diff --git a/unit-tests/test-cases/rpath-executable_path/bar.c b/unit-tests/test-cases/rpath-executable_path/bar.c
new file mode 100644 (file)
index 0000000..31a758c
--- /dev/null
@@ -0,0 +1,8 @@
+extern void foo();
+
+void bar()
+{
+       foo();
+}
+
+
diff --git a/unit-tests/test-cases/rpath-executable_path/foo.c b/unit-tests/test-cases/rpath-executable_path/foo.c
new file mode 100644 (file)
index 0000000..1624757
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-executable_path/main.c b/unit-tests/test-cases/rpath-executable_path/main.c
new file mode 100644 (file)
index 0000000..4612793
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void bar();
+
+int main()
+{
+       bar();
+       PASS("rpath-executable_path");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-indirect-suid/Makefile b/unit-tests/test-cases/rpath-indirect-suid/Makefile
new file mode 100644 (file)
index 0000000..a1ec99e
--- /dev/null
@@ -0,0 +1,71 @@
+##
+# 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
+
+
+#
+# a setuid main executable linked with -rpath links against a dylib 
+# that uses rpath to find another dylib.  It is an error if
+# LC_RPATH uses @loader_path or a relative path, but ok if it is an absolute path
+#
+
+
+run: all
+       ./main || echo "FAIL rpath-indirect-suid absolute path"
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid @loader_path path" "rpath-indirect-suid @loader_path path" ./main_bad1
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid relative path" "rpath-indirect-suid relative path" ./main_bad2
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid @rpath spoof" "rpath-indirect-suid @rpath spoof" ./main_bad3
+
+all: main main_bad1 main_bad2 main_bad3
+
+hide/hole/libbar.dylib : bar.c
+       mkdir -p hide/hole
+       ${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 
+
+main : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,`pwd`/hide/hole
+       sudo chown root main
+       sudo chmod 4755 main
+
+main_bad1 : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -DDEFAULT_FAIL  -o main_bad1 libfoo.dylib -Wl,-rpath -Wl,@loader_path/hide/hole
+       sudo chown root main_bad1
+       sudo chmod 4755 main_bad1
+
+main_bad2 : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -DDEFAULT_FAIL -o main_bad2 libfoo.dylib -Wl,-rpath -Wl,hide/hole
+       sudo chown root main_bad2
+       sudo chmod 4755 main_bad2
+
+main_bad3 : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -DDEFAULT_FAIL -o main_bad3 libfoo.dylib 
+       ln -s hide/hole @rpath
+       sudo chown root main_bad3
+       sudo chmod 4755 main_bad3
+
+clean:
+       ${RM} ${RMFLAGS} *~  main main_bad1 main_bad2 main_bad3 hide libfoo.dylib @rpath
diff --git a/unit-tests/test-cases/rpath-indirect-suid/bar.c b/unit-tests/test-cases/rpath-indirect-suid/bar.c
new file mode 100644 (file)
index 0000000..b1b8fd7
--- /dev/null
@@ -0,0 +1,6 @@
+
+void bar()
+{
+}
+
+
diff --git a/unit-tests/test-cases/rpath-indirect-suid/foo.c b/unit-tests/test-cases/rpath-indirect-suid/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/rpath-indirect-suid/main.c b/unit-tests/test-cases/rpath-indirect-suid/main.c
new file mode 100644 (file)
index 0000000..bdea9f9
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+#if DEFAULT_FAIL
+       FAIL("rpath-indirect-setuid");
+#else
+       PASS("rpath-indirect-setuid");
+#endif
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/Makefile b/unit-tests/test-cases/rpath-loader_path-dlopen/Makefile
new file mode 100644 (file)
index 0000000..d83c5e8
--- /dev/null
@@ -0,0 +1,53 @@
+##
+# Copyright (c) 2006-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
+
+
+#
+# a main executable linked with -rpath that uses @loader_path.
+# The @loader_path in the rpath should expand at runtime to the directory
+# of the main executable during calls to dlopen()
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libbaz.dylib : baz.c
+       mkdir -p hide/hole
+       ${CC} baz.c -dynamiclib -o hide/hole/libbaz.dylib -install_name @rpath/libbaz.dylib
+       
+libbar.dylib : bar.c hide/hole/libbaz.dylib
+       ${CC} bar.c -dynamiclib -o libbar.dylib hide/hole/libbaz.dylib
+
+libfoo.dylib : foo.c libbar.dylib
+       ${CC} foo.c -dynamiclib -o libfoo.dylib 
+
+main : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main -Wl,-rpath -Wl,@loader_path/hide/hole libfoo.dylib
+
+clean:
+       ${RM} -rf *~  main hide libbar.dylib libfoo.dylib 
\ No newline at end of file
diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/bar.c b/unit-tests/test-cases/rpath-loader_path-dlopen/bar.c
new file mode 100644 (file)
index 0000000..f9c0742
--- /dev/null
@@ -0,0 +1,8 @@
+extern void baz();
+
+void bar()
+{
+       baz();
+}
+
+
diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/baz.c b/unit-tests/test-cases/rpath-loader_path-dlopen/baz.c
new file mode 100644 (file)
index 0000000..0793d97
--- /dev/null
@@ -0,0 +1,6 @@
+
+void baz()
+{
+}
+
+
diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/foo.c b/unit-tests/test-cases/rpath-loader_path-dlopen/foo.c
new file mode 100644 (file)
index 0000000..92d2257
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+bool foo()
+{
+       return (dlopen("./libbar.dylib", RTLD_NOW) != NULL);
+}
diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/main.c b/unit-tests/test-cases/rpath-loader_path-dlopen/main.c
new file mode 100644 (file)
index 0000000..2b1cc25
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 <stdbool.h>
+
+#include "test.h"
+
+extern bool foo();
+
+int main()
+{
+       if ( foo() ) 
+               PASS("rpath-loader_path-dlopen");
+       else
+               FAIL("rpath-loader_path-dlopen: %s", dlerror());
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-loader_path/Makefile b/unit-tests/test-cases/rpath-loader_path/Makefile
new file mode 100644 (file)
index 0000000..6bd18a9
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# a main executable linked with -rpath that uses @loader_path.
+# The @loader_path in the rpath should expand at runtime to the directory
+# of the binary.
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide/hole/libfoo.dylib : foo.c
+       mkdir -p hide/hole
+       ${CC} foo.c -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,@loader_path/hide/hole
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide
diff --git a/unit-tests/test-cases/rpath-loader_path/foo.c b/unit-tests/test-cases/rpath-loader_path/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-loader_path/main.c b/unit-tests/test-cases/rpath-loader_path/main.c
new file mode 100644 (file)
index 0000000..bf6c7fa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       PASS("rpath-basic");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-nesting/Makefile b/unit-tests/test-cases/rpath-nesting/Makefile
new file mode 100644 (file)
index 0000000..0364549
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The main executable supplies an rpath.  libfoo.dylib supplies an 
+# rpath.  libfoo.dylib needs libbar.dylib and libbaz.dylib.  One
+# is found from the main executable's rpath and one from libfoo.dylib's
+# rpath. 
+#
+
+
+run: all
+       ./main
+
+all: main
+
+hide1/libbar.dylib : bar.c
+       mkdir -p hide1
+       ${CC} bar.c -dynamiclib -o hide1/libbar.dylib  -install_name @rpath/libbar.dylib
+       
+hide2/libbaz.dylib : baz.c
+       mkdir -p hide2
+       ${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
+
+main : main.c libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,`pwd`/hide1
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide1 hide2 libfoo.dylib
diff --git a/unit-tests/test-cases/rpath-nesting/bar.c b/unit-tests/test-cases/rpath-nesting/bar.c
new file mode 100644 (file)
index 0000000..d47ba49
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+void bar()
+{
+}
+
+
diff --git a/unit-tests/test-cases/rpath-nesting/baz.c b/unit-tests/test-cases/rpath-nesting/baz.c
new file mode 100644 (file)
index 0000000..dc61b62
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+void baz()
+{
+}
+
+
diff --git a/unit-tests/test-cases/rpath-nesting/foo.c b/unit-tests/test-cases/rpath-nesting/foo.c
new file mode 100644 (file)
index 0000000..7b46c28
--- /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@
+ */
+extern void bar();
+extern void baz();
+void foo()
+{
+       bar();
+       baz();
+}
diff --git a/unit-tests/test-cases/rpath-nesting/main.c b/unit-tests/test-cases/rpath-nesting/main.c
new file mode 100644 (file)
index 0000000..47d3ae2
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       
+       PASS("rpath-nesting");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/shared-cache-symlink/Makefile b/unit-tests/test-cases/shared-cache-symlink/Makefile
new file mode 100644 (file)
index 0000000..92ea1b0
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# 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
+
+run: all
+       ./main
+
+all: main 
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main 
+
diff --git a/unit-tests/test-cases/shared-cache-symlink/main.c b/unit-tests/test-cases/shared-cache-symlink/main.c
new file mode 100644 (file)
index 0000000..ab1c6b6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 <stdint.h>
+#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()
+
+// libz.1.dylib should be in the shared cache
+// libz.dylib is a symlink to libz.dylib
+// we want to verify that dlopening the symlink name will use the one in the shared cache
+
+
+int main()
+{
+       void* libzHandle = dlopen("/usr/lib/libz.dylib", RTLD_LAZY);
+       if ( libzHandle == NULL ) {
+               FAIL("shared-cache-symlink: dlopen(/usr/lib/libz.dylib, RTLD_LAZY) failed: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       // get address of strcmp()
+       void* sym = dlsym(libzHandle, "inflate");
+       if ( sym == NULL ) {
+               FAIL("shared-cache-symlink: dlsym(handle, \"inflate\") failed");
+               return EXIT_SUCCESS;
+       }
+       
+       Dl_info info;
+       if ( dladdr(sym, &info) == 0 ) {
+               FAIL("shared-cache-symlink: dladdr(sym, xx) failed");
+               return EXIT_SUCCESS;
+       }
+
+       // walk images to get slide
+       uint32_t count = _dyld_image_count();
+       for(uint32_t i=0; i < count; ++i) {
+               if ( _dyld_get_image_header(i) == info.dli_fbase ) {
+                       if ( _dyld_get_image_vmaddr_slide(i) == 0 ) {
+                               // images in shared cache have a slide of zero
+                               PASS("shared-cache-symlink");
+                               return EXIT_SUCCESS;
+                       }
+                       else {
+                               FAIL("shared-cache-symlink: libz.dylib not loaded from shared cache");
+                               return EXIT_SUCCESS;
+                       }
+               }
+        }
+
+       FAIL("shared-cache-symlink libz.dylib not found");
+       return EXIT_SUCCESS;
+}
index 07dcdef0766a277addf802adffcd46ac8180e3a4..8ef3c6d5a6dc74859c6e944cee686fe0fafa5f40 100644 (file)
@@ -29,7 +29,7 @@ run: all
 all: main
 
 main: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c
        sudo chown root main
        sudo chmod 4755 main
 
diff --git a/unit-tests/test-cases/suid-executable_path/Makefile b/unit-tests/test-cases/suid-executable_path/Makefile
new file mode 100644 (file)
index 0000000..1dd7f1e
--- /dev/null
@@ -0,0 +1,82 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Use of @exectuable_path in setuid binaries is not allowed
+# Use of @loader_path in setuid binaries is not allowed
+# Use of relative paths in setuid binaries is not allowed
+#
+
+run: all
+       ./main_exe "setuid-executable_path" || echo "FAIL setuid-executable_path @executable_path not setuid"
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path @executable_path" "setuid-executable_path @executable_path" ./main_exe-suid "setuid-executable_path"
+       ./main_loader "setuid-executable_path" || echo "FAIL setuid-executable_path @loader_path not setuid" 
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path @loader_path" "setuid-executable_path @loader_path" ./main_loader-suid "setuid-executable_path"
+       ./main_rel "setuid-executable_path" || echo "FAIL setuid-executable_path relative path not setuid" 
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path relative path" "setuid-executable_path relative path" ./main_rel-suid "setuid-executable_path"
+
+
+
+all: main_exe main_exe-suid    main_loader main_loader-suid    main_rel main_rel-suid
+
+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
+       cp main_exe main_exe-suid
+       sudo chown root main_exe-suid
+       sudo chmod 4755 main_exe-suid
+       
+main_loader: main.c dir2/libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main_loader main.c dir2/libbar.dylib
+       cp main_loader main_loader-suid
+       sudo chown root main_loader-suid
+       sudo chmod 4755 main_loader-suid
+
+main_rel: main.c dir3/libbaz.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main_rel main.c dir3/libbaz.dylib
+       cp main_rel main_rel-suid
+       sudo chown root main_rel-suid
+       sudo chmod 4755 main_rel-suid
+
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main_exe main_exe-suid main_loader main_loader-suid main_rel main_rel-suid dir1 dir2 dir3
+
diff --git a/unit-tests/test-cases/suid-executable_path/foo.c b/unit-tests/test-cases/suid-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/suid-executable_path/main.c b/unit-tests/test-cases/suid-executable_path/main.c
new file mode 100644 (file)
index 0000000..aa63e85
--- /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 <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();
+       if ( issetugid() )
+               FAIL(argv[1]);
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/template/Makefile b/unit-tests/test-cases/template/Makefile
new file mode 100644 (file)
index 0000000..b0ee016
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# 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
+
+run: all
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/template/main.c b/unit-tests/test-cases/template/main.c
new file mode 100644 (file)
index 0000000..083736b
--- /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@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int
+main(int argc, const char* argv[])
+{
+  PASS("template");
+  return EXIT_SUCCESS;
+}
index 77e16cc0e61646ecd25a05fd1c6a345521dd3ca5..fd4ad9bdf7ab085a022aeadc6759c87fd5633af3 100644 (file)
@@ -38,7 +38,7 @@ run: all
 all: main libfoo.dylib
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
 
 libfoo.dylib : foo.c libbar_missing.dylib libbar.dylib
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib libbar.dylib
index 2a87dad312b10f995ce4c8988371e20f949ee393..fc39c25cc37da8fdf167df0d2eb3376fc5220f9d 100644 (file)
@@ -39,6 +39,7 @@ int main()
         uint32_t count = _dyld_image_count();
         for(uint32_t i=0; i < count; ++i) {
                const char*  name = _dyld_get_image_name(i);
+               //fprintf(stderr, "%s\n", name);
                if (strcmp(name, "libfoo.dylib") == 0 ) {
                        FAIL("library-cant-be-bound: libfoo.dylib shows up in list of images");
                        return 0;
index d958a78ee7941198b49d86d6a268e56746238eee..372c29aa877000fa7760b941e838796f645aec1b 100644 (file)
@@ -29,6 +29,9 @@
 // it calls myfunc() 
 extern int foo();
 
+// add this so WEAK_DEFINES is set, so dyld searchs this image
+int __attribute__((weak)) junk = 2;
+
 int main()
 {
        if ( foo() == 10 )
index f49610dad3a8972c80fa43e48219844cb5f5029b..ba1d7aaf805b4da5efe8b0902855ff538894f0f3 100644 (file)
@@ -36,7 +36,7 @@ libfoo_missing.dylib : foo.c
        ${CC} -dynamiclib -o libfoo_missing.dylib foo.c -install_name libfoo.dylib
 
 main: main.c libfoo.dylib
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -I${TESTROOT}/include -L. -lfoo -o main  main.c -flat_namespace
+       ${CC} -I${TESTROOT}/include -mmacosx-version-min=10.2 -L. -lfoo -o main  main.c -flat_namespace
 
 clean:
        ${RM} ${RMFLAGS} *~ libfoo.dylib libfoo_missing.dylib main
diff --git a/unit-tests/test-cases/zero-fill-segment/Makefile b/unit-tests/test-cases/zero-fill-segment/Makefile
new file mode 100644 (file)
index 0000000..513cd75
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
+
+
+run: all
+       ./main 
+
+all: main
+
+
+main: main.c foo.bundle
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+       
+foo.bundle : foo.c zero.s
+               ${CC} ${CCFLAGS} -bundle foo.c zero.s -o foo.bundle
+
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle
+
diff --git a/unit-tests/test-cases/zero-fill-segment/foo.c b/unit-tests/test-cases/zero-fill-segment/foo.c
new file mode 100644 (file)
index 0000000..4202b55
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern int foo[];
+
+int getfoo(int x)  
+{ 
+       return foo[x]; 
+}
+
diff --git a/unit-tests/test-cases/zero-fill-segment/main.c b/unit-tests/test-cases/zero-fill-segment/main.c
new file mode 100644 (file)
index 0000000..0676756
--- /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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h> // dlopen()
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int
+main(int argc, const char* argv[])
+{
+       void* handle = dlopen("foo.bundle", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("zero-fill-segment: dlopen(\"%s\") failed with: %s", "foo.bundle", dlerror());
+               exit(0);
+       }
+       
+       void* sym = dlsym(handle, "getfoo");
+       if ( sym == NULL ) {
+               FAIL("zero-fill-segment: dlsym(handle, \"getfoo\") failed");
+               exit(0);
+       }
+       
+       dlclose(handle);
+
+       PASS("zero-fill-segment");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/zero-fill-segment/zero.s b/unit-tests/test-cases/zero-fill-segment/zero.s
new file mode 100644 (file)
index 0000000..cfb52ea
--- /dev/null
@@ -0,0 +1,5 @@
+
+.globl _foo
+.zerofill __MYZERO, __zero, _foo, 8192
+
+
diff --git a/unit-tests/test-cases/zero-length-segment/Makefile b/unit-tests/test-cases/zero-length-segment/Makefile
new file mode 100644 (file)
index 0000000..9d8b5cb
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# 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
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+run: all
+       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
+
+
+all: main
+
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+       
+libfoo.dylib : foo.c
+               ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-sectcreate -Wl,__FOOBAR -Wl,__empty -Wl,/dev/null
+
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib segments.log
+
diff --git a/unit-tests/test-cases/zero-length-segment/foo.c b/unit-tests/test-cases/zero-length-segment/foo.c
new file mode 100644 (file)
index 0000000..85e6cd8
--- /dev/null
@@ -0,0 +1 @@
+void foo() {}
diff --git a/unit-tests/test-cases/zero-length-segment/main.c b/unit-tests/test-cases/zero-length-segment/main.c
new file mode 100644 (file)
index 0000000..f5a0e5d
--- /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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int
+main(int argc, const char* argv[])
+{
+  return EXIT_SUCCESS;
+}