]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-210.2.3.tar.gz mac-os-x-108 mac-os-x-1081 mac-os-x-1082 mac-os-x-1083 mac-os-x-1084 mac-os-x-1085 v210.2.3
authorApple <opensource@apple.com>
Fri, 27 Jul 2012 18:00:50 +0000 (18:00 +0000)
committerApple <opensource@apple.com>
Fri, 27 Jul 2012 18:00:50 +0000 (18:00 +0000)
124 files changed:
doc/ReleaseNotes.txt [new file with mode: 0644]
doc/man/man3/dlopen.3
dyld.xcodeproj/project.pbxproj
include/mach-o/dyld_gdb.h
include/mach-o/dyld_priv.h
include/objc-shared-cache.h [new file with mode: 0644]
launch-cache/Architectures.hpp
launch-cache/MachOBinder.hpp
launch-cache/MachOFileAbstraction.hpp
launch-cache/MachOLayout.hpp
launch-cache/MachORebaser.hpp
launch-cache/ObjCLegacyAbstraction.hpp
launch-cache/ObjCModernAbstraction.hpp
launch-cache/dsc_extractor.cpp
launch-cache/dsc_iterator.cpp
launch-cache/dsc_slider.cpp [deleted file]
launch-cache/dsc_slider.h [deleted file]
launch-cache/dyld_cache_format.h
launch-cache/dyld_shared_cache_util.cpp
launch-cache/update_dyld_shared_cache.cpp
src/ImageLoader.cpp
src/ImageLoader.h
src/ImageLoaderMachO.cpp
src/ImageLoaderMachO.h
src/ImageLoaderMachOClassic.cpp
src/ImageLoaderMachOCompressed.cpp
src/dyld.cpp
src/dyld.h
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemGlue.c
src/dyldLibSystemInterface.h
src/dyldStartup.s
src/dyld_debug.c
src/glue.c
src/start_glue.s [new file with mode: 0644]
src/stub_binding_helper.s
unit-tests/build-iPhoneOS-unit-tests
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c
unit-tests/test-cases/addend/main.c
unit-tests/test-cases/bundle-memory-load-fat/Makefile
unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c
unit-tests/test-cases/crt-apple/Makefile
unit-tests/test-cases/crt-apple/main.c
unit-tests/test-cases/crt-custom/Makefile
unit-tests/test-cases/crt-custom/mystart.s
unit-tests/test-cases/dlopen_preflight-cycle/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-cycle/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-cycle/baz.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-cycle/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-cycle/main.c [new file with mode: 0644]
unit-tests/test-cases/dyld-slide/Makefile [deleted file]
unit-tests/test-cases/dyld-slide/main.c [deleted file]
unit-tests/test-cases/fallback-non-unique-leaf-names/main.c
unit-tests/test-cases/image-state-deny-all_image_infos/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-all_image_infos/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-all_image_infos/main.c [new file with mode: 0644]
unit-tests/test-cases/image-suffix/main.c
unit-tests/test-cases/initializer-bounds-check/Makefile
unit-tests/test-cases/initializer-bounds-check/main.c
unit-tests/test-cases/insert-libraries-with-suid/Makefile
unit-tests/test-cases/interpose-shared-cache/main.c
unit-tests/test-cases/interpose-shared-cache/mymalloc.c
unit-tests/test-cases/loader_path-symlink/Makefile [new file with mode: 0644]
unit-tests/test-cases/loader_path-symlink/bar.c [new file with mode: 0644]
unit-tests/test-cases/loader_path-symlink/foo.c [new file with mode: 0644]
unit-tests/test-cases/loader_path-symlink/main.c [new file with mode: 0644]
unit-tests/test-cases/pie-text-reloc/Makefile
unit-tests/test-cases/re-export-symbol-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/baz.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/baz.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/foo.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/frob.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/Makefile
unit-tests/test-cases/read-only-stubs/main.c
unit-tests/test-cases/restrict-environ/Makefile
unit-tests/test-cases/rpath-dlopen-rm-executable/main.c
unit-tests/test-cases/rpath-introspection/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-introspection/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-introspection/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-loader_path-dlopen/main.c
unit-tests/test-cases/suid-environ/Makefile
unit-tests/test-cases/symbol-resolver-basic/Makefile
unit-tests/test-cases/symbol-resolver-interposed/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-interposed/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-interposed/foo.h [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-interposed/main.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-interposed/myfoo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-pointer/Makefile
unit-tests/test-cases/terminator-bounds-check/Makefile [new file with mode: 0644]
unit-tests/test-cases/terminator-bounds-check/main.c [new file with mode: 0644]
unit-tests/test-cases/text-relocs-perms/foo.c
unit-tests/test-cases/text-relocs-perms/main.c
unit-tests/test-cases/text-relocs/Makefile
unit-tests/test-cases/text-relocs/space.s
unit-tests/test-cases/tlv-initializer/Makefile
unit-tests/test-cases/tlv-initializer/get.s
unit-tests/test-cases/tlv-initializer/main.c
unit-tests/test-cases/tlv-terminators/Makefile
unit-tests/test-cases/upward-dylib-init-order/Makefile [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/b.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/c.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/common.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/common.h [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/main.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib-init-order/u.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/Makefile
unit-tests/test-cases/upward-dylib/down.c
unit-tests/test-cases/upward-dylib/down.h
unit-tests/test-cases/upward-dylib/main.c
unit-tests/test-cases/upward-dylib/main2.c [new file with mode: 0644]

diff --git a/doc/ReleaseNotes.txt b/doc/ReleaseNotes.txt
new file mode 100644 (file)
index 0000000..33ce9ad
--- /dev/null
@@ -0,0 +1,1769 @@
+
+dyld-208
+<rdar://problem/10879179> Correct @path to still work with symlinks
+
+dyld-207
+<rdar://problem/10825175> dyld should give a better error message if you try to use a newer binary on older OS
+<rdar://problem/10753356> backtraces of LC_MAIN binaries end in tlv_get_addr+136, instead libdyld should export "_start" symbol
+<rdar://problem/10733082> Fix up @rpath based paths during introspection
+<rdar://problem/10657737> Interposition tuples are not respected when binding with resolvers
+
+dyld-206
+<rdar://problem/10442813> Give some warning that DYLD_ env vars are disabled
+
+dyld-205
+<rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
+
+dyld-204.1
+<rdar://problem/10643239> fix initializer ordering of upwardly linked dylibs
+
+dyld-204
+<rdar://problem/10613880> dyld misreads very large addends
+<rdar://problem/10568559> Perform method list sort even if __DATA,__objc_opt_rw is absent
+<rdar://problem/10568179> Remove category attaching from dyld shared cache
+<rdar://problem/10582497> Shared cache method list sorting breaks protocol extended type encodings
+
+dyld-203.1
+<rdar://problem/10491874> initializer not run in only upwardly linked dylib
+
+dyld-203
+<rdar://problem/10419267> update_dyld_shared_cache does not build with libc++
+<rdar://problem/10435247> dyld does not build with libc++
+<rdar://problem/10409027> Add functions to get min OS and sdk versions program was linked with
+<rdar://problem/10399676> DYLD_FRAMEWORK_PATH not mentioned in dlopen() man page
+<rdar://problem/10371927> dsc_extractor not updating LC_FUNCTION_STARTS
+
+dyld-202
+<rdar://problem/8818423> Get rid of crt1.o and jump straight into main() from dyld
+<rdar://problem/10332417> image denied loading by gc_enforcer is left in dyld_all_images_info array
+
+dyld-201
+<rdar://problem/8867781> Use spin lock to guard sAllImageInfos
+
+dyld-200.3
+<rdar://problem/9855733> genCaches fails: "header size miscalculation 0x00006000"
+
+dyld-200.2
+<rdar://problem/9784634> dsc_iterator.cpp needs cases for v7 variants
+
+dyld-200
+<rdar://problem/8942979> update_dyld_shared_cache should accept an 'overlay' along with a 'root' directory option
+Remove PowerPC support
+
+--------------
+dyld-199.5 (iOS 5)
+<rdar://problem/9955829> Update initial image list size
+
+dyld-199.4
+<rdar://problem/9855733> genCaches fails: header size miscalculation
+
+dyld-199.3 
+<rdar://problem/7338034> Repair ivar offsets in dyld shared cache
+
+dyld-199.2
+<rdar://problem/8981046> improve Xcode upload of iOS dylibs
+
+dyld-199.1
+<rdar://problem/9510382> correctly adjust ARM movw when in dyld shared cache
+
+dyld-199
+<rdar://problem/9439764> update_dyld_shared_cache requires weak-linked frameworks to be present at shared cache generation time
+<rdar://problem/9447838> Remove armv7 variants from dyld
+
+dyld-198.1
+<rdar://problem/8312145> back out previous change DYLD_XXX restrict check
+
+dyld-198
+<rdar://problem/9035759> corrupt load commands can pass sniff test if 32-bit wraps around
+<rdar://problem/8312145> dyld should restrict DYLD_XXX debugging facilities
+<rdar://problem/7942521> dyld should not allow loading of dylibs without valid signatures
+enable DYLD_PRINT_REBASINGS
+
+dyld-197
+<rdar://problem/7945496> dyld should range check the fixup location of all bindings
+<rdar://problem/8963406> range check initializers and terminators to be within image
+
+dyld-196.2
+<rdar://problem/8987681> dyld should support new armv7 variants
+
+dyld-196.1
+<rdar://problem/9107912> support re-exported symbols from re-exported libraries
+
+dyld-196
+<rdar://problem/9078764> movw/movt don't work in dyld shared cache
+
+
+---------------------
+dyld-195.3 (Mac OS X 10.7.0)
+<rdar://problem/9279770> update_dyld_shared_cache missed libstdc++?
+<rdar://problem/9361288> i386 dyld shared cache overflows after adding libclh.dylib
+
+dyld-195.2
+<rdar://problem/9161945> spurious warning about embedded framework not being put in dyld shared cache
+
+dyld-195
+<rdar://problem/8360915> C++ 0x thread_local destructor support
+<rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
+<rdar://problem/8971061> more verbose messages when vm_protect() fails 
+
+dyld-194.1
+Fix uses of libc++abi-static.a
+
+dyld-194
+<rdar://problem/8919005> make interposing available to open source
+<rdar://problem/8874282> __thread implementation doesn't preserve enough registers (ABI issue)
+<rdar://problem/8873628> clang built update_dyld_shared_cache fails at runtime
+
+dyld-193
+<rdar://problem/8735709> dyld should honor CS_RESTRICT in _main like hasRestrictedSegment
+<rdar://problem/8164591> update_dyld_shared_cache -overlay optimizations
+
+dyld-192.1
+<rdar://problem/8812589> dyld has NULL paths in image info array
+
+dyld-192
+<rdar://problem/8750829> dyld's map+slide should be an all or nothing operation 
+
+dyld-191.3
+<rdar://problem/8890875> overriding shared cache dylibs with resolvers fails
+dyld-191.2
+<rdar://problem/8844174> dyld_stub_binder called repeatedly for $VARIANT$ functions
+<rdar://problem/8845480> update_dyld_shared_cache crash when fat dylib truncated
+
+dyld-191.1
+<rdar://problem/8770940> update_dyld_shared_cache is failing
+
+dyld-191
+<rdar://problem/8736495> ASLR/PIE: dyld's "random padding" algorithm is deterministic
+<rdar://problem/8663923> race condition with flat-namespace lazy binding
+<rdar://problem/8755380> libdyld fails to build with clang-127
+
+dyld-190.1
+remove libdyld.a target
+
+dyld-190
+<rdar://problem/8706192> _NSGetExecutablePath documentation is ambiguous about bufsize
+<rdar://problem/8686676> 11A315: LC_DYLD_ENVIRONMENT does not expand @executable_path
+<rdar://problem/8718137> dyld should avoid arc4random for dylib randomization
+<rdar://problem/8691207> tune trie traversal code for 10.7 compiler
+<rdar://problem/8576479> breaking libSystem into dylibs slows down dyld binding, shared cache should compensate
+<rdar://problem/8686427> update_dyld_shared_cache should not be built no-pie
+
+dyld-189
+<rdar://problem/8274426> dyld(1) man page feedback
+<rdar://problem/8564762> LC_DYLD_ENVIRONMENT should still be honored with __RESTRICT,__restrict section present
+<rdar://problem/8630416> 11A307: DYLD_SHARED_REGION=private crashes
+<rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
+
+dyld-188
+<rdar://problem/4472406> Dynamic linking memory usage seems unusually high for trivial programs
+
+dyld-187
+<rdar://problem/8597637> madvise MADV_FREE calls for LINKEDIT are failing in dyld during launch in iOS
+<rdar://problem/8602453> dyld allImageInfos messed up with duplicate IOKit
+
+dyld-186
+<rdar://problem/8109857> dyld: Pick up changes from libsystem_kernel reorganisation in dyld's build.
+<rdar://problem/5847052> Shared Region Base Should Slide at Boot Time 
+<rdar://problem/6650578> Multiple /dev/urandom accesses on every process exec
+
+dyld-185
+<rdar://problem/8345025> text relocs don't work if only S_ATTR_EXT_RELOC is used
+<rdar://problem/8400815> DYLD_FORCE_FLAT_NAMESPACE=YES causes process to spin in DYLD-STUB$$bzero
+
+dyld-184
+<rdar://problem/8554137> Add cache slide value to dyld_all_image_infos
+
+dyld-183.1
+<rdar://problem/8521882> dyld proper does not need dyld_stub_binder.o
+
+dyld-183
+<rdar://problem/8274192> dyld needs to call new kernel interface to register metadata
+<rdar://problem/8448281> ASLR side build causes 15-30% regression in most launch times
+<rdar://problem/8440902> Support version-checked framework/library override paths
+<rdar://problem/8440934> Support LC_DYLD_ENVIRONMENT load command
+<rdar://problem/8454987> function starts info should be copied into dyld shared cache
+
+dyld-182
+<rdar://problem/8432001> Merge Jasper dyld changes to trunk
+
+dyld-181.1
+<rdar://problem/8455429> 11A270: FNPLicensingService crashes
+
+dyld-181
+<rdar://problem/8403002> 11A238a: AutoDesk AutoCAD beta 4 crashes on launch (dyld)
+<rdar://problem/8345799> update_dyld_shared_cache-173 project fails to build with LLVM compiler 2.0.
+
+dyld-180
+<rdar://problem/8352892> 8F63: dyld-179.4 fails on missing /usr/local/lib/system/libc.a
+<rdar://problem/8344449> 11A238a: AutoDesk AutoCAD beta 4 crashes on launch
+<rdar://problem/8313034> 11A244: overlapping files in libdyld & update_dyld_shared_cache
+
+
+dyld-179.7 (iOS 4.2)
+<rdar://problem/8543820> range check initializers
+
+dyld-179.6 
+<rdar://problem/8515776> dyld_shared_cache_extract_dylibs shouldn't return '-1' when arch already exists
+
+dyld-179.5 
+<rdar://problem/8425790> Need a version of dyld_shared_cache_extract_dylbs that lipo's results
+<rdar://problem/8365622> Need a version of dyld_shared_cache_extract_dylbs that reports progress
+<rdar://problem/8320866> back out work around for 8151909
+
+dyld-179.4
+<rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
+
+dyld-179.3.1
+<rdar://problem/8327834> 11A245: Photoshop CS4 fails in SmokeTest because of crash in FNPLicensingService (dyld)
+
+dyld-179.3
+<rdar://problem/8305049> 11A238a: All Adobe CS4 applications crash on launch
+
+dyld-179.2
+<rdar://problem/8290793> 11A239: leaks throws an exception, doesn't work
+
+dyld-179.1
+<rdar://problem/8284123> libdsc.a in Jasper SDK needs to be arm version (is x86 version)
+
+dyld-179
+<rdar://problem/8284944> update_dyld_shared_cache does not work with individual symbol re-exports
+
+dyld-178
+<rdar://problem/8284044> Support __thread variables exported from dylibs
+<rdar://problem/7356532> update dyld_all_image_infos more often, for better crash logs
+
+dyld-177
+<rdar://problem/8214567> We need an extractor able to pull the shared symbols cache apart
+<rdar://problem/8263666> Don't put slide info in dyld shared cache in Jasper
+<rdar://problem/8268602> dyld does not prevent loading of unsigned dylib
+
+dyld-176
+<rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
+
+dyld-175
+<rdar://problem/8235734> ObjC optimized shared cache does not slide
+
+dyld-174
+<rdar://problem/8198287> Need to merge Apex ObjC method list optimizations in dyld shared cache to TOT dyld
+<rdar://problem/8115131> implement ASLR for dyld shared cache for iOS
+
+dyld-173
+<rdar://problem/8144421> fix permissions on rebased binary not slid
+
+dyld-172.2
+<rdar://problem/8191063> dyld should not include SystemIntegrity headers on embedded platform
+Have DYLD_PRINT_BINDINGS print out when resolver functions are called
+
+dyld-172.1
+<rdar://problem/8166086> fix visibility of dyld_func_lookup depending if libdyld is .a or .dylib
+
+dyld-172
+Add hack to work around 8151909
+Alter project to build for both kinds of libSystems
+
+dyld-171
+Add support for individual symbol re-exports
+Add support for building for iOS
+
+dyld-170
+<rdar://problem/7508424> ER: more metadata for dyld errors
+
+dyld-169
+<rdar://problem/7995213> update_dyld_shared_cache needs to support resolver functions
+Implement some cxa stuff to work with next c++abi.a
+
+dyld-168
+<rdar://problem/7901042> dyld should move shared cache file into /var/run instead of open-unlinking
+<rdar://problem/7940222> private shared cache calls mmap twice for each range
+<rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
+<rdar://problem/7935000> 11A168: update_dyld_shared_cache problems during install
+<rdar://problem/7918210> use of C++ thread local initializer causes infinite recursion
+<rdar://problem/7932725> (from iPhoneOS) dyld should stub out mach_error_string for 8KB RAM savings per process
+<rdar://problem/7937695> (from iPhoneOS) verify that replacement is in this image
+
+dyld-167.2
+<rdar://problem/7956031> dyld: Use libsystem_mach.a from /usr/local/lib/dyld to build dyld
+
+dyld-167.1
+<rdar://problem/7901042> dyld should move shared cache file into /tmp instead of open-unlinking
+
+dyld-167
+<rdar://problem/7859049> dyld support for function specialization
+<rdar://problem/7740779> dyld should directly call __cxa_finalize(), part 2
+<rdar://problem/7796738> dyld support for thread local variables
+
+
+dyld-166
+<rdar://problem/7739489> ER: facility to detect which images were loaded at runtime
+<rdar://problem/7818451> update_dyld_shared_cache -verify fails
+
+
+dyld-165
+<rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
+<rdar://problem/7744084> Sort method lists in dyld shared cache
+
+
+dyld-164
+<rdar://problem/7733433> Move libdyldapis over to a dylib target for Libsystem
+<rdar://problem/7675254> pruneEnvironmentVariables does not update gLinkContext.apple
+
+
+dyld-163
+<rdar://problem/7740033> Warning message is misleading
+<rdar://problem/7740658> update_dyld_shared_cache should not run past end of splitseginfo if zero terminator is missing
+<rdar://problem/6666832> dyld should directly call __cxa_finalize(), part 1
+
+
+dyld-162
+<rdar://problem/7662176> crash in update_dyld_shared_cache when checking if current cache is out of date
+<rdar://problem/7444994> ER: Support upward dylib dependencies
+
+
+dyld-161
+<rdar://problem/7628929> __builtin_return_address broke for PPC
+<rdar://problem/7658265> SWBDC error: 'ld: duplicate symbol' while building 'dyld-160~48' in '11A108a-llvmgcc-2324.3'
+
+
+dyld-160
+<rdar://problem/7234280> Environment variable to cause dyld to dump rpaths used during loading
+<rdar://problem/7595563> update_dyld_shared_cache failed: internal error, new trie allocated to far from fLinkeditBase
+<rdar://problem/7589167> dyld still slides executables when PIE is disabled by the kernel
+
+
+dyld-159
+<rdar://problem/7343139> update_dyld_shared_cache fails to find roots when targetting NFS
+<rdar://problem/7484408> dyld does not call initializers from all S_MOD_INIT_FUNC_POINTERS sections
+<rdar://problem/7544082> move _dyld_func_lookup prototype to dyld_priv.h
+
+
+dyld-158
+<rdar://problem/7486405> dyld attempts to load libraries via rpath when already loaded
+<rdar://problem/5274722> dyld shared cache can be more random
+
+
+dyld-157
+<rdar://problem/7481480> switch to use libc++abi-static.a instead of libstdc++-static.a
+
+
+dyld-156
+<rdar://problem/7408768> remove DYLD_NO_PIE from man page
+<rdar://problem/7445102> support multiple dylibs with non-intersected weak symbols in shared cache
+<rdar://problem/7466900> dyld sends bogus library unload notice to CoreSymbolication during dlopen_preflight()
+<rdar://problem/7455017> spelling: "was build against" -> "was built against"
+
+
+dyld-155
+<rdar://problem/7451030> sjlj based exception support needs to be conditionalized for arm - not iPhoneOS
+
+
+dyld-154
+<rdar://problem/7272661> Need to enable CoreSymbolication load/unload notices on iPhoneOS
+
+
+dyld-153
+<rdar://problem/7327864> add field to dyld_all_image_infos pointing to dyld_all_image_infos
+
+
+dyld-152
+<rdar://problem/7302432> Minimize system calls and mach messages during dyld startup
+<rdar://problem/7302383> Why is checkSharedRegionDisable() !__LP64__
+
+
+dyld-151
+<rdar://problem/7223037> dyld support for sliding PIE binaries in the kernel
+<rdar://problem/7165731> libdyld does not install multiple headers at installhdrs time
+<rdar://problem/6937560> dlopen() crash when executable contains LC_RPATH and executable file is deleted while running
+<rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
+
+
+----------------------------------
+
+dyld-150  ( iPhoneOS 3.1 )
+<rdar://problem/7043575> flat_namespace linkage error in update_dyld_shared_cache should be a warning not an error
+<rdar://problem/7084861> Have dyld save load addr + UUID for executable images
+<rdar://problem/7101832> Libsystem fails to link with latest gcc: dyld missing _dyld_func_lookup
+
+
+dyld-149
+<rdar://problem/7017050> dlopen() not working with non-canonical paths
+<rdar://problem/7033445> update_dyld_shared_cache fails creating shared cache
+
+
+dyld-148
+<rdar://problem/7022281> shared cache file offsets are inconsistent
+
+
+dyld-147
+<rdar://problem/6995143> move install location for update_dyld_shared_cache and man page to local
+<rdar://problem/7014995> imageFileModDate in dyld_all_image_infos is sometimes bogus for the first image therein
+<rdar://problem/7014397> dyld_shared_cache_util should optionally print VM load addresses for each dylib
+<rdar://problem/7014783> uuid_t not defined in dyld_priv.h
+
+
+dyld-146
+<rdar://problem/7008875> Save load information (load addr + UUID) to dyld_all_image_infos for images from outside the shared cache
+<rdar://problem/7007923> update_dyld_shared_cache should improve warning above deployment target
+
+
+dyld-145
+<rdar://problem/7000405> optimize stubs in dyld shared cache to be no-PIC
+<rdar://problem/6995143> dyld_shared_cache_util built by dyld target should go in platform directory
+<rdar://problem/7001159> dyld_shared_cache_util should list LC_REEXPORT_DYLIB libraries as dependents
+
+
+dyld-144
+<rdar://problem/6995143> dyld_shared_cache_util built by dyld target should go in platform directory
+<rdar://problem/6775261> API: Detect shared cache overrides
+
+
+dyld-143
+<rdar://problem/6956867> ER: Tool to list the contents of a dyld shared cache image
+<rdar://problem/6959334> ARM support for dsc_iterator
+
+
+dyld-142
+<rdar://problem/6965455> text relocs fail in large segments
+<rdar://problem/6945944> Variable whose data is overwritten needs to be marked `volatile'
+<rdar://problem/6921370> dyld option to print time for each initializer, Apple's or the app's
+
+
+dyld-141
+<rdar://problem/6927281> update_dyld_shared_cache assumes -root path contains no symlinks
+sync with SnowLeopard dyld-132.13
+
+
+dyld-140
+<rdar://problem/6153040> load code signature from file, and before mapping the file
+
+
+dyld-139.1
+<rdar://problem/6868811> Northstar7C62: dyld-139 fails to build
+
+
+dyld-139
+<rdar://problem/6780449> dyld on iPhoneOS uses libgcc_eh.a which uses pthread_key_create which does not work
+<rdar://problem/6780192> dyld can leak when an internal exception in thrown
+<rdar://problem/6331300> support compressed LINKEDIT on iPhone
+sync with SnowLeopard dyld-132.11
+
+
+dyld-138.1
+<rdar://problem/6790993> New mechanism to instruct dyld whether to check for libs outside the shared cache
+
+
+dyld-138
+<rdar://problem/6814596> need to handle symlinks when dylib is in cache but file is intentionally missing
+<rdar://problem/6825135> dyld should avoid stat()ing libraries present in the shared cache unless magic override file is present
+
+
+dyld-137 
+<rdar://problem/6792383> dyld reports image not found if it is in the shared cache but no binary is present on disk
+sync with SnowLeopard dyld-132.10
+
+
+dyld-136
+<rdar://problem/6776343> dyld reports bogus fat offset when registering shared cache signature
+
+
+dyld-135
+<rdar://problem/6268421> iPhone: Need objc optimizations in iPhone OS shared cache
+
+
+dyld-134
+<rdar://problem/4759373> build armv6 dyld with Thumb
+sync with SnowLeopard
+
+
+
+dyld-133.1
+fix for all arm architectures
+
+
+dyld-133
+<rdar://problem/6268380> make dyld that uses shared cache on iPhone OS
+
+
+----------------------------------
+
+dyld-132.13 ( Mac OS X 10.6 )
+<rdar://problem/6898370> classic images not unmapped when unloaded
+
+
+dyld-132.12 
+<rdar://problem/6882159> dyld's dtrace notification should be done after rebasing
+
+
+dyld-132.11 
+<rdar://problem/6803496> Remove dyld workaround for McAfee VirusScan
+<rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
+
+
+dyld-132.10
+<rdar://problem/6785160> dyld's abort_report_np() doesn't abort
+<rdar://problem/6794063> 10A331: CUPS crashes when calling sandbox_init
+
+
+dyld-132.9 
+<rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
+<rdar://problem/6739742> Exception Backtrace being obscured by _mh_execute_header
+<rdar://problem/6766057> Silverlight Preferences.app crashes
+
+
+dyld-132.8 
+<rdar://problem/6735870> dlopen() leaks send right obtained from mach_thread_self()
+<rdar://problem/6732715> dyld's calloc() allocates too few bytes
+<rdar://problem/6678640> dyld lazy binding is not thread safe
+
+
+dyld-132.7
+<rdar://problem/6651342> need a way other than setgid to have dyld launch a process securely, ignoring DYLD_ env vars etc
+<rdar://problem/6721803> Need mapping of files to their offsets into the dyld_shared_cache files on disk
+
+
+dyld-132.6
+<rdar://problem/6618466> update_dyld_shared_cache -overlay should check root dyld caches
+<rdar://problem/6619554> NSCreateObjectFileImageFromMemory() call vm_deallocate even if application used malloc()
+
+
+dyld-132.5
+<rdar://problem/6655235> dyld is missing some binding optimizations
+<rdar://problem/6647316> symbol lookups in the new trie structure should be faster
+<rdar://problem/6570879> weak binding done too early with inserted libraries
+
+
+dyld-132.4
+<rdar://problem/6629428> improve statistics output
+<rdar://problem/6628413> better error message if LC_RPATH is used in dylib destined for shared cache
+<rdar://problem/6622898> dladdr() broke when image has debug symbols
+<rdar://problem/6555720> 10A264: Google Earth 5.0 crashes on quit 
+<rdar://problem/6591933> man page should better explain update_dyld_shared_cache -root option
+
+
+dyld-132.3
+<rdar://problem/6527653> remove setjmp/longjmp from _simple_printf in dyld
+<rdar://problem/6580333> Typo in dyld(3) man page
+<rdar://problem/6510301> race condition in pre-10.6 style lazy pointer binding
+<rdar://problem/6573344> make cheaper dladdr() that just returns image path
+<rdar://problem/6563887> 10A266 - Adobe InDesign CS4 crashes on launch
+<rdar://problem/6570113> dyld is not setting imageFileModDate in dyld_image_info
+<rdar://problem/6493245> Logic Pro crashes after creating a new document on SnowLeopard
+
+
+dyld-132.2
+<rdar://problem/6293143> adopt new CoresSymbolication notification mechanism
+<rdar://problem/6536810> Alter libdyld.a to not need libsystem to link with dylib1.o
+<rdar://problem/6530593> 10A256a: update_dyld_shared_cache -verify crashes (probably due to lack of a shared cache)
+
+
+dyld-132.1
+<rdar://problem/6552051> update_dyld_shared_cache failed: no writable segment in Cocoa framework
+
+
+dyld-132
+<rdar://problem/6490500> CrashTracer: [USER] 1 crash in Neverwinter Nights 2 
+
+
+dyld-131
+<rdar://problem/6501078> libgmalloc broken on 10A10246 and 10A251 (libgmalloc not inserted early enough)
+
+
+dyld-130
+<rdar://problem/6497528> Rosetta circular dependency spew
+<rdar://problem/6347414> @rpath and @loader_path Should be Documented in man page
+Prune unneeded load commands from shared cache images
+
+
+dyld-129
+<rdar://problem/6479007> dyld-128 no longer builds for armv6
+<rdar://problem/6481443> 10A244: iTunes crashes trying to load MobileDevice.framework
+
+
+dyld-128
+<rdar://problem/6474295> ImageLoader objects can be made smaller
+<rdar://problem/6198151> dyld spin in SecurityAgent
+<rdar://problem/6285470> ImageLoaderMachO::makeImportSegmentWritable() doesn't do it
+
+
+dyld-127
+<rdar://problem/6464419> Add all_image_infos for CrashReporter
+some fixes for compressed LINKEDIT 
+
+
+dyld-126
+<rdar://problem/6459812> x86_64 export trie nodes may have large negative address
+<rdar://problem/6442327> update_dyld_shared_cache man page should be updated to reflect new SL behavior
+
+
+dyld-125
+<rdar://problem/6347414> @rpath and @loader_path should be documented in man page
+<rdar://problem/6421511> Add NOP after trap instruction in _dyld_fatal_error
+
+
+dyld-124
+<rdar://problem/6273311> update_dyld_shared_cache should not automatically run by default
+Add support for arm shared caches
+Add support for __program_vars section
+Add more -verify sanity checks
+
+
+dyld-123
+<rdar://problem/6117580> Add -verify option to update_dyld_shared_cache
+<rdar://problem/6408758> [dyld] Errors reported by the upcoming compiler flags verifier
+<rdar://problem/6408518> 10A224: update_dyld_shared_cache warns about a condition in B&I-built frameworks
+<rdar://problem/4697610> stop shadowing old data structures
+<rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
+
+
+dyld-122
+<rdar://problem/6361143> Need a way to determine if a gdb call to dlopen() would block
+<rdar://problem/6328003> Drop Rosetta shared cache generation by default / at install
+<rdar://problem/6400750> "terminaton function" misspelled
+<rdar://problem/6399150> Make it easier to use shared caches from foreign systems
+<rdar://problem/6369189> SnowLeopard10A210: MATLAB 7.6 crashes on launch
+
+
+dyld-121.1
+<rdar://problem/6364434> CrashTracer: crash in iTunes at com.apple.QuickTimeComponents.component 
+
+
+dyld-121
+<rdar://problem/6373929> libdyld.a is missing dyld_stub_binder
+
+
+dyld-120
+<rdar://problem/6315338> 10A197 - After Effects 8.0.2 fails to launch after installation 
+
+
+dyld-119
+<rdar://problem/6364540> 10A212: update_dyld_shared_cache failed: string buffer exhausted
+<rdar://problem/6357561> Oracle client crashes
+
+
+dyld-118.1
+<rdar://problem/6350500> Cope with duplicate protocol references in shared cache construction
+
+
+dyld-118
+<rdar://problem/6336723> 10A197 vs 10A190: Applications warm launch time slowdown due to dyld
+
+
+dyld-117
+<rdar://problem/6318449> 10A198 - Final Cut Pro 6.0.4 crashes on launch [INTRODUCED BY dyld-115 IN 10A197]
+
+
+dyld-116
+<rdar://problem/6004942> Pandora Desktop (Adobe AIR Framework) crashes on launch [INTRODUCED BY dyld-101 IN 10A14]
+<rdar://problem/6250902> dyld should use libunwind
+<rdar://problem/5408556> Possible leak originating in speech at LoadEngine
+<rdar://problem/6315314> update_dyld_shared_cache manpage typos 'parition', 'assignes', 'choosen'
+
+
+dyld-115
+<rdar://problem/6061574> LINKEDIT content could be greatly compressed
+
+
+dyld-114
+<rdar://problem/6231688> update_dyld_shared_cache needs to provide progress that the Installer can display
+<rdar://problem/6231686> update_dyld_shared_cache needs to be able to look at an Installation sandbox
+<rdar://problem/6293143> dyld isn't calling csdlc_notify on library unload
+<rdar://problem/6277916> warning, could not bind Mail.app because realpath() failed on /AppleInternal/.../XILog.framework
+
+
+dyld-113
+<rdar://problem/6252320> NSAddressOfSymbol(NULL) should return NULL and not crash
+<rdar://problem/6255192> dlopen() should fail to load (non-pie) executables
+
+
+dyld-112
+<rdar://problem/6188100> _replacement misspelled as _replacement in dyld-interposing.h
+<rdar://problem/6176037> make _dyld_find_unwind_sections() faster
+
+
+dyld-111
+<rdar://problem/6161821> improve bad relocation error message
+<rdar://problem/6190458> Need load/unload notification sent to com.apple.vmudl service when requested
+<rdar://problem/6188100> _replacement misspelled as _replacement in dyld-interposing.h
+
+
+dyld-110
+<rdar://problem/5703616> check libSystem is correct in shared cache file before loading it
+<rdar://problem/5557882> function names returned by dladdr do not match reality
+<rdar://problem/5780431> update_dyld_shared_cache .map files should be written atomically
+<rdar://problem/6145451> dlopen(RTLD_NOLOAD) does not need to throw an internal exception
+<rdar://problem/4090265> Explanation for the RTLD_NEXT flag in dlsym(3) needs clarification
+<rdar://problem/5951327> DYLD_FALLBACK_LIBRARY_PATH should not apply to dlopen() of a partial path
+<rdar://problem/6182301> No shared cache present on first boot
+
+
+dyld-109
+<rdar://problem/5925940> Safe Boot should disable dyld shared cache
+<rdar://problem/5706594> CrashTracer: crash in preFetch() reading off end of LINKEDIT
+<rdar://problem/6109435> DYLD_NO_PIE env variable should be documented in dyld manpage
+<rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
+<rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+
+
+dyld-108.1
+<rdar://problem/6156702> armv7/armv5 specific settings needed for dyld
+<rdar://problem/6156653> dyld shouldn't set VALID_ARCHS
+
+
+dyld-108
+<rdar://problem/6120723> ER: dyld based Objective-C selector uniquing
+
+
+dyld-107
+<rdar://problem/5274720> update_dyld_shared_cache should require all source dylibs be owned by root
+<rdar://problem/6073702> Limit what might go in the dyld shared cache
+<rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
+<rdar://problem/5505043> Grow initial dyld pool if needed
+<rdar://problem/5807857> there should be some way to temporarily turn off -pie
+<rdar://problem/6050482> If pie, ignore preferred load address
+<rdar://problem/6053800> Put all_image_infos in its own section to it is easy to find
+
+
+dyld-106
+allow update_dyld_shared_cache to be build 64-bit
+<rdar://problem/5280258> dyld error handling fails in low memory, _simple_salloc() result not checked
+<rdar://problem/4047718> dyld should provide executing program name in incompatible cpu-subtype error message
+
+
+dyld-105
+<rdar://problem/5957134> It should work to set DYLD_FALLBACK_LIBRARY_PATH to empty
+<rdar://problem/5366292> Remove the exceptions made in 4804594 for filemaker
+<rdar://problem/5922117> Remove Tiger-era hacks in dyld for old app compatibility
+<rdar://problem/5901958> Make RTLD_MAIN_ONLY public
+<rdar://problem/5819435> die more gracefully when load commands are malformed
+<rdar://problem/5953438> SWB: dyld build failure when built with -fstack-protector
+<rdar://problem/5950134> dyld man page mis-spelling
+<rdar://problem/5943045> update_dyld_shared_cache does not work when run manually
+
+
+dyld-104
+<rdar://problem/5901583> The optimization to reuse install names as fPath was lost
+<rdar://problem/5888343> Add JIT field to dyld_all_image_infos
+Add _dyld_find_unwind_sections()
+
+
+dyld-103
+<rdar://problem/5805956> NSLinkModule() can crash
+<rdar://problem/5620189> dyld: obsoleted deprecated APIs
+work around for <rdar://problem/5736393>
+add test cases for lazy dylib loading
+
+
+dyld-102
+<rdar://problem/5394977> Man page typo for update_dyld_shared_cache
+<rdar://problem/5490738> Add "malloc is initialized" to the dyld_all_image_infos struct
+<rdar://problem/4045952> better handling of open() errors
+<rdar://problem/5377739> remove <mach-o/dyld_debug.h>
+<rdar://problem/5629960> Use <mach/shared_region.h> instead of <mach/shared_memory_server.h>
+<rdar://problem/5775824> dyld and libdyld should not force building with gcc 4.0
+
+
+dyld-101
+<rdar://problem/5725845> make it easier to find dyld_all_image_infos
+<rdar://problem/5363402> Need _dyld_get_image_slide(const struct mach_header* mh)
+<rdar://problem/5708213> dyld: push code signatures for libs to kernel
+
+
+dyld-100
+<rdar://problem/4737476> dyld falls over when asked to map a split seg library not in the shared region
+<rdar://problem/5595695> dyld: interposing does not work when replacee is thumb
+<rdar://problem/5596017> dyld: all PIE programs crash on launch
+<rdar://problem/5575446> BigBear: not loading libraries at their preferred addresses
+<rdar://problem/5490089> dyld support for arm subtypes
+<rdar://problem/5539483> dyld's prefetching should be turned off for prebound images (and perhaps entirely?)
+<rdar://problem/5602284> dyld-95.3 doesn't build with gcc 4.2
+merge in arm support
+<rdar://problem/5504633> ADOBE: Premiere Pro crashes on quit
+
+----------------------------------
+
+dyld-96.2 (Mac OS X 10.5.2)
+<rdar://problem/5694507> 10.5.2 Regression: 9C18 MeetingMaker crash on launch
+
+dyld-96.1
+<rdar://problem/5537155> update_dyld_shared_cache can crash if dylibs modified out from under it
+<rdar://problem/5562562> crash when dyld interposes on system with partially invalid cache
+<rdar://problem/5563394> com.apple.dyld message spew
+<rdar://problem/5565230> CFSTRs cause crashes in Leopard
+<rdar://problem/5566103> if system shuts down during update_dyld_shared_cache, tmp file is never cleaned up
+<rdar://problem/5623353> dlopen() and dlopen_preflight() can leak on failure
+
+
+
+dyld-95.3 (Mac OS X 10.5)
+<rdar://problem/5503905> Increase initial dyld pool size for 64-bit programs
+
+
+dyld-95.2
+<rdar://problem/5495438> make ppc dyld cache a different file for rosetta
+
+
+dyld-95.1
+<rdar://problem/5388895> McAfee VirusScan fails to launch on Leopard9A513
+
+
+dyld-95
+<rdar://problem/5392427> 9A516 - Keep getting disk full errors
+
+
+dyld-94
+<rdar://problem/5366233> Leopard (9a499): dyld crash with recursive calls to dlclose()
+
+
+dyld-93
+<rdar://problem/4804594> FileMaker Server 8.0v4 helper tools broken by @executable_path security change
+<rdar://problem/5364239> Use msync(MS_SYNC) when building dyld cache
+
+
+dyld-92
+<rdar://problem/5322907> Skype Crashes during launch
+
+
+dyld-91.2
+<rdar://problem/5313172> dlopen() looks too far up stack, can cause crash
+
+
+dyld-91.1
+<rdar://problem/5288790> dyld warning about dtracehelper is too noisy?
+<rdar://problem/5311611> Lots of task_self_trap() system calls in ImageLoader::recursiveInitialization()
+
+
+dyld-91
+<rdar://problem/5249477> use of @loader_path based RPATH can cause dyld to leak
+<rdar://problem/4910107> Dyld_stubs should not be writable on x86
+
+
+dyld-90.2
+<rdar://problem/4860414> generating dyld shared cache generation on first boot makes time to MacBuddy very slow
+
+
+dyld-90.1
+<rdar://problem/5274718> truncated dyld cache file after panic causes hang at boot
+
+
+dyld-90
+<rdar://problem/4892216> stop special casing main executables initializers
+<rdar://problem/4170040> DYLD_INSERT_LIBRARIES doesn't work correctly with initializer functions
+
+
+dyld-89
+<rdar://problem/5097116> dyld could asynchronously request pages it will need
+<rdar://problem/5272001> handle when argv[0] is NULL.
+<rdar://problem/5186317> Foundation built on 9A436 doesn't launch 64 bit apps
+partial fix for: <rdar://problem/4910107> Dyld_stubs should not be writable on x86
+
+
+dyld-88
+<rdar://problem/5233126> update_dyld_shared_cache keeps spewing messages to console
+<rdar://problem/4795421> optimize LINKEDIT region of dyld shared cache
+<rdar://problem/5244184> Support extended __dyld section with NXArgc, etc addresses
+remove call to __xlocale_init()
+Update __OPEN_SOURCE__ conditionals
+
+
+dyld-87
+<rdar://problem/5203587> CFM games use private _dyld_fork_* routines - add back
+<rdar://problem/5231152> better handling of NOLOAD with symlinked dylibs
+
+
+dyld-86.1
+Fix DYLD_SHARED_REGION=private
+update man page
+
+
+dyld-86
+<rdar://problem/4960876> update_dyld_shared_cache fails on @executable_path framework
+<rdar://problem/5213017> [Leopard]: 9A441/442: unable to log in after switching to arabic
+<rdar://problem/5221505> dlopen via CFBundleLoad keeps searching after finding a loadable object
+
+
+dyld-85.2
+<rdar://problem/5202525> MatLab 2007a (7.4) doesn't launch on Leopard9A441
+Never optimize ppc shared cache on intel
+Fix LINKEDIT size in shared cache .map files
+Fix how PIEs are moved to work with NX
+Call pthread_init_keys to work with latest Libc
+
+
+dyld-85.1
+<rdar://problem/5215536> Leopard9A447: Meeting Maker and Microsoft apps will not launch on Intel.
+
+
+dyld-85
+<rdar://problem/5193485> 9A436: Adobe: Photoshop CS3 crashed on pressing Command-C after Command-A
+<rdar://problem/4892382> Use _dyld_initializer
+
+
+dyld-84
+<rdar://problem/5194274> 9A438 dlopen_preflight() corrupts all_image_info list causing Symbolication crashes
+<rdar://problem/5195384> B&I needs an ENV variable to turn off "dyld: ioctl to register dtrace DOF section failed" warnings
+<rdar://problem/4819036> remove support for __image_notify sections
+remove all update_prebinding code
+
+
+dyld-83
+<rdar://problem/4819047> use _simple_dprintf() instead of fprintf()
+remove -progress option from update_dyld_shared_cache
+update_dyld_shared_cache no longer tells rosetta to flush its caches
+<rdar://problem/5110291> update_dyld_shared_cache error message gives an errno value rather than an error string
+<rdar://problem/3968392> dyld interposing doesn't work with dlsym() lookup
+<rdar://problem/5163803> dlopen_preflight() of MH_BUNDLE leaks
+<rdar://problem/5067898&5184629> integrate ImageLoader changes into leopard dyld
+<rdar://problem/5179640> translated (ppc) dyld should not attempt to register DOF sections
+<rdar://problem/5135363> Some dyld library paths are not canonicalized, causing tools using those paths to defenestrate themselves
+
+
+dyld-82.5
+<rdar://problem/5147450> REGR: Leopard9A419: Firefox hangs on launch
+
+
+dyld-82.4
+<rdar://problem/5150283> Leopard9A420: interposing of libMallocDebug or libgmalloc broken
+Fix so problems like <rdar://problem/5149971> are warnings instead of errors
+
+
+dyld-82.3
+<rdar://problem/5148533> 9A420: dyld: ioctl to register dtrace DOF section failed
+
+
+dyld-82.2
+<rdar://problem/5135896> dyld frees string returned by dyld_image_state_change_handler
+<rdar://problem/5133621> better handling than "corrupt binary, library ordinal too big"
+
+
+dyld-82.1
+<rdar://problem/5125295> dyld changes needed to support read-only DOF
+
+
+
+dyld-82
+<rdar://problem/5115360> don't need to hold dyld global lock while running initializers
+<rdar://problem/5094847> dyld leaks when dlopen fails
+<rdar://problem/5128758> dyld leaks two blocks after bundle unload
+
+
+dyld-81
+<rdar://problem/5016782> auto update dyld shared caches if missing or out of date
+
+
+dyld-80.1
+<rdar://problem/5090212> Erronious "unsafe use of @rpath" dyld error
+<rdar://problem/5066570> 9A384: update_dyld_shared_cache fails after ditto'ing matador root with debug info
+<rdar://problem/5093704> Uninitialized ImageLoader->fRegisteredDOF field
+
+
+dyld-80 (Leopard9A400)
+<rdar://problem/4971149> Use new shared region syscalls
+<rdar://problem/5073851> @rpath does not work with -rpath @executable_path/...
+<rdar://problem/5067376> Firefox causes segfault during update_dyld_shared_cache
+
+
+dyld-79.3
+<rdar://problem/4971149> Use new shared region syscalls
+
+dyld-79.2
+<rdar://problem/5073851> @rpath does not work with -rpath @executable_path/...
+
+dyld-79.1 (Leopard9A396)
+fix use of LC_REEXPORTED_DYLIB
+
+
+dyld-79 (Leopard9A392)
+<rdar://problem/5039911> Support Apple PIE (address space randomization)
+<rdar://problem/5055814> update_dyld_shared_cache should warning and not quit if a specified root is missing
+<rdar://problem/5058918> DOF registration needs to switch from /dev/helper to /dev/dtracehelper
+<rdar://problem/5042252> don't error out when a cache line crossing i386 stub cannot be bound
+
+
+dyld-78.2 (Leopard9A387)
+<rdar://problem/5050338> 9A385: Mail (anything using Message.framework) takes a ridiculous amount of time to launch
+
+
+dyld-78.1 (Leopard9A385)
+Fix override of _malloc_lock to be data instead of code
+
+
+dyld-78
+<rdar://problem/5040417> when loading a bundle, dyld is not making a copy of name
+<rdar://problem/5001598> 9A343 KidPix 3 : SpellChecker bundle is not loaded
+<rdar://problem/5028176> dyld cache does not recognize dynamic load of library via symbolic link
+
+
+dyld-77.1
+Back out 4892382 until B&I build fleet has fixed kernel
+
+
+dyld-77
+<rdar://problem/4892382> Use _dyld_initializer
+<rdar://problem/4838967> Look at reduction/elimination of per-framework cost (don't touch __dyld section)
+<rdar://problem/4920999> libdyldapis.a: make initialization as lean as possible
+<rdar://problem/3896792> dyld should malloc never-to-be-freed blocks from its own pool
+<rdar://problem/4980326> Libraries feeding into Libsystem should contain version numbers (libdyldapis)
+Install update_prebinding symlink
+Addend warnings to end of shared cache .map files
+Conditionalize away update_prebinding support
+dladdr() should not remove 's' from "start"
+
+
+dyld-76.2
+<rdar://problem/4987676> hang at boot, Libc changes
+
+dyld-76.1
+<rdar://problem/4979617> x86_64: dyld share cache does not work for AppKit
+
+
+dyld-76
+<rdar://problem/4958744> Rosetta apps crash after update_dyld_shared_cache
+<rdar://problem/4953905> Long-standing typo for "file to short" error from dlopen() / dlerror()
+
+
+dyld-75.1
+Enable ppc shared cache generation on intel machines
+
+
+dyld-75
+<rdar://problem/4931772> 64-byte crossing fast stubs should be bound early to avoid threading issues
+<rdar://problem/4217374> support new intel stub segment that is marked not-writable
+
+
+dyld-74
+<rdar://problem/4893418> register dtrace DOF sections with kernel
+<rdar://problem/4898960> 10.4.9 Regression: Math Kernel crash with TiNovi 8P114
+
+
+dyld-73.2
+<rdar://problem/4889617> Leopard 9A921: Dyld error "lazy pointer not found" loading/running java
+
+
+dyld-73.1 (Leopard9A328)
+<rdar://problem/4883565> 9A326: update_prebinding crashes at end of install
+
+
+dyld-73 (Leopard9A326)
+<rdar://problem/4876600> REGR: 9A322 All Java apps crashing at dyld's misaligned_stack_error
+
+
+dyld-72 (Leopard9A322)
+<rdar://problem/4853532> Maya 8 crashes on launch on Leopard9A309
+<rdar://problem/4791766> ProTools 7.1.1cs1 for Intel hangs on launch on Leopard9A309
+<rdar://problem/4388957> x86 crashes in the binding helper do not have proper backtrace
+
+
+dyld-71  (Leopard9A320)
+<rdar://problem/4824553> inform rosetta of each library in the dyld shared cache
+<rdar://problem/4853825> 9A316: Dreamweaver MX 2004 crashes on launch in dyld's addImage
+
+
+dyld-70 (Leopard9A315)
+support split-seg dylibs built with LC_SEGMENT_SPLIT_INFO
+support --progress option in update_dyld_shared_cache so that installer can run it
+
+
+dyld-69.1 (Leopard9A309)
+<rdar://problem/4826097> 9A305: Firefox 2.0 crashes on launch
+<rdar://problem/4827641> httpd is dying in dyld after libobjc.dylib is unloaded
+
+
+dyld-69 (Leopard9A305)
+<rdar://problem/3532018> ER: dlclose() should be able to unload dylibs
+<rdar://problem/3584130> runtime support for RPATH
+
+
+dyld-68 (Leopard9A296)
+<rdar://problem/4797707> rosetta doesn't work when shared cache is present
+<rdar://problem/4800592> shared cache for 64-bit archs does not work when some dylibs are invalid
+
+
+dyld-67.1 (Leopard9A292)
+<rdar://problem/4754048> support 64-bit programs built with new 10.5 subtype
+
+
+dyld-67
+<rdar://problem/4764143> CrashReporter needs a new way to distinguish fatal dyld errors
+<rdar://problem/4610810> support dlopen(NULL, RTLD_FIRST)
+Move base address of ppc64 dyld to match new memory layout
+Move base address of 64-bit shared caches to match new memory layout
+Move location of shared cache file to /var/db/dyld
+Add support for LC_REEXPORT_DYLIB
+Use shared cache if it exists
+Requires ld64-63.1 or later built dylibs for shared cache generation
+
+
+dyld-66.3 (Leopard9A276)
+<rdar://problem/4742808> dyld fails to build with Libc changes in 4632326
+<rdar://problem/4754048> support 64-bit programs built with new 10.5 subtype
+
+
+dyld-66.2 (Leopard9A260)
+<rdar://problem/4718046> Leopard9A259: Backtraces in crash reports are not getting symbolicated
+<rdar://problem/4714894> dyld should get rosetta process name from standard location
+
+
+dyld-66.1 (Leopard9A259)
+Fix for build breakage with Libc-436
+
+
+dyld-66 
+Preliminary shared cache support
+<rdar://problem/4109087> <mach-o/dyld_gdb.h> is in Darwin but not Dev Tools package
+<rdar://problem/4710378> export shared range regions for gdb
+<rdar://problem/4697552> __pthread_tsd_first appears to be initialized too late in dyld
+<rdar://problem/4589305> don't use @executable_path or fallback searching in setuid programs
+
+
+dyld-65.1 (Leopard9A252)
+fix B&I build failure with Libc-435
+
+
+dyld-65 (Leopard9A247)
+<rdar://problem/4653725> jump table entry at end of segment can crash
+<rdar://problem/4644563> Mathematica 5.2 (64-bit MathKernel) always crashes on 9A229
+<rdar://problem/4088447> dlsym man page needs to be more specific about RTLD_DEFAULT
+<rdar://problem/4092461> Change wording in SEARCHING section in dlopen man page
+<rdar://problem/4560992> Man page for dyld has misspelling: cheep
+<rdar://problem/4579459> dyld(3) man page should point to Mach-O Programming Topics URL
+
+
+dyld-64 (Leopard9A224)
+<rdar://problem/4620487> No man page for dlopen_preflight(3)
+<rdar://problem/4363960> dyld lazy binding of fast stubs is not completely thread safe
+<rdar://problem/4628677> remove use of load_shared_file()
+
+
+dyld-63 (Leopard9A215)
+<rdar://problem/4530861> Would like way to quiet dynamic loader
+<rdar://problem/4513256> deprecated old APIs for Leopard
+<rdar://problem/4590713> NSCreateObjectFileImageFromMemory crashes when image is a MH_EXECUTABLE
+
+
+dyld-62.1 (Leopard9A206)
+<rdar://problem/4598215> prebound old stubs failure prevents uTest from running on i386
+
+
+dyld-62 (Leopard9A202)
+<rdar://problem/4589041> an image with an open non-zero base address does not load more efficiently
+<rdar://problem/4590567> Leopard9A190: NSAddImage() crashes when called from x86_64 process
+<rdar://problem/4578484> /usr/lib/libAPSimple.dylib: mmap error
+<rdar://problem/4557971> need to force interposing for rosetta processes
+
+
+dyld-61 (Leopard9A179)
+<rdar://problem/4528739> dyld calls close(-1)
+<rdar://problem/4506173> _stub_binding_helper_interface isn't using movdqa
+<rdar://problem/4548652> dyld tries to mmap 0 size segments and fails with conforming mmap
+<rdar://problem/4536652> Load dyld above 4GB for x86-64
+Move apple parameters on stack when DYLD_ variables are removed
+
+
+dyld-60 (Leopard9A160)
+<rdar://problem/4379896> Suresec #203: dyld environment with suid binaries
+<rdar://problem/4148690> SureSec si#187 linker: environment variables
+<rdar://problem/3915210> print warning message if DYLD_INSERT_LIBRARIES is set (then ignored) for a setuid/setgid program
+<rdar://problem/4359815> dyld's disableIfBadUser() routine can fail for constant strings
+
+
+dyld-59 (Leopard9A156)
+<rdar://problem/4452274> ER: dlopen_preflight()
+
+
+dyld-58 (Leopard9A154)
+<rdar://problem/3827070> implement RTLD_SELF
+<rdar://problem/4045952> better handling of open() errors
+<rdar://problem/4198200> would like dlopen(RTLD_FIRST) so that dlsym variant that does not search dependent libraries
+<rdar://problem/4508801> dyld needs to adopt to Unix conformance changes
+<rdar://problem/4507650> Crash on Leopard9A146 when GC rejects loading a library on Intel
+
+
+dyld-57 (Leopard9A144)
+<rdar://problem/4423668> pthread tsd entries doubly owned by DYLD and Libsystem... (Leopard)
+<rdar://problem/4492351> dyld should automatically stop using the shared region if unavailable
+<rdar://problem/4494723> If instantiateFromLoadedImage fails, dyld crashes
+<rdar://problem/4494725> isCompatibleMachO needs to know about x86-64
+
+
+dyld-56 (Leopard9A140)
+<rdar://problem/3908479> 64-bit dyld should load at around the last 4G - not in the first 4G
+<rdar://problem/4486559> 64 bit: app crashes immediately if -pagezero_size >= 0x0ffffffff
+<rdar://problem/4486804> dyld needs to build for x86-64
+<rdar://problem/4149233> dyld_debug API shim has leak
+<rdar://problem/4490848> dyld does not slide properly on Intel
+
+
+dyld-55 (Leopard9A138)
+<rdar://problem/4430145> dlopen() should fail if bundle has objc code incompatible with runtime environment
+<rdar://problem/4340954> libdyld: make non-POSIX header definitions visible when _POSIX_C_SOURCE is defined
+<rdar://problem/4393607> A flat_namespace image with a reference to an internal private_extern should resolve immediately
+<rdar://problem/4401777> dlopen() man page is missing RTLD_NOLOAD and RTLD_NODELETE
+<rdar://problem/4427324> _CFExecutableLinkedOnOrAfter() fails on 64 bit
+<rdar://problem/4442283> dyld needs to support x86-64
+
+
+dyld-54 (Leopard9A80)
+<rdar://problem/4030730> remove ppc64 workarounds for fixed bugs
+<rdar://problem/4051922> Memory error in removePathWithPrefix()
+<rdar://problem/4258921> dyld does not properly swap CPU subtype from fat file header
+<rdar://problem/4361806> dyld does not compile for open source
+<rdar://problem/4363188> ADOBE XCODE 2.2: ZeroLink can cause wrong typeinfos to be used
+Sync with Chardonnay (except for 4313830 and 4215516)
+
+
+dyld-53 (Leopard9A42)
+<rdar://problem/4254657> Add -fno-exceptions to Release target of libdyld
+<rdar://problem/4326451> Wrong number of seconds reported by DYLD_PRINT_STATISTICS on Intel
+
+
+dyld-52 (Leopard9Axxx)
+<rdar://problem/4172797> dyld changes for new libstdc++ project
+
+
+dyld-51 (Clueless)
+<rdar://problem/3866740> STD:VSX: dlclose() should return non-zero value on failure.
+<rdar://problem/3944469> STD:BUILD: dyld references non-conforming member name for PPC64
+<rdar://problem/4116234> The gdb list of images should be updated before dyld bases and binds each image
+<rdar://problem/3916854> interposing does not handle stacking/nesting of interposing functions
+<rdar://problem/4090063> use of DYLD_INTERPOSE() causes compiler warnings with -std=c99 -pedantic
+<rdar://problem/3992272> SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371
+
+dyld-50 (Leopard9Axxx)
+Convert to build with gcc-4.0
+<rdar://problem/3992272> SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371
+
+----------------------------------
+
+
+
+dyld-46.16 (Mac OS X 10.4.11) 
+<rdar://problem/5146059&5334400> raise bail out limit in update_prebinding to 100 errors
+
+dyld-46.15
+<rdar://problem/5334280> [SUIncaSoho] update_prebinding can only handle 2MB of ppc unprebound dylibs on intel
+<rdar://problem/5146059&5334400> update_prebinding fails if a prebound dylib depends on a non-prebound dylib
+
+dyld-46.14
+<rdar://problem/4814545&5260830> prebinding zeroes out files if an error occurs (such as no vm space left)
+<rdar://problem/4948045&5257758> Rare & unknown root cause: Corruption of Kerberos framework during SU
+
+dyld-46.13
+<rdar://problem/4975286> dyld crashes starting threaded program
+<rdar://problem/5050570> 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state
+<rdar://problem/5116499> 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state
+<rdar://problem/5160205> [SUTiSoHo] update_prebinding crashes when a weak linked dylib is missing
+<rdar://problem/5165777> [SUIncaSoHo] update_prebinding crashes when a weak linked dylib is missing
+
+dyld-46.12
+<rdar://problem/4898960> 10.4.9 Regression: Math Kernel crash with TiNovi 8P114
+
+dyld-46.11
+<rdar://problem/4642940> dyld's x86_64 support should be open source
+<rdar://problem/4604221> 10.4.x: an image with an open non-zero base address does not load more efficiently
+<rdar://problem/4864380> [SUTiNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately
+<rdar://problem/4870982> [SUTiNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7
+<rdar://problem/4765099> [SUIncaNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7
+<rdar://problem/4864373> [SUIncaNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately
+
+dyld-46.10
+<rdar://problem/4787033> dyld-46.9 fails to build in Nicoya
+
+dyld-46.9 (Inca8K...)
+<rdar://problem/4653725> jump table entry at end of segment can crash
+
+dyld-46.8 (Inca8K1073)
+<rdar://problem/4645490> Mathematica 5.2 (64-bit MathKernel) always crashes on Inca
+
+dyld-46.7 (Inca8K1072)
+<rdar://problem/4622201> dyld lazy binding of fast stubs is not completely thread safe
+
+dyld-46.6 (Inca8K1061)
+<rdar://problem/4607261> Inca: don't write warning to stderr for setuid binaries
+
+dyld-46.5 (Inca8K1059)
+<rdar://problem/4598215> prebound old stubs failure prevents uTest from running on i386
+
+dyld-46.4 (Inca8K1057)
+<rdar://problem/4590567> NSAddImage() crashes when called from x86_64 process
+<rdar://problem/4589041> an image with an open non-zero base address does not load more efficiently
+
+dyld-46.3 (Inca8K1054)
+<rdar://problem/4557971> need to force interposing for rosetta processes
+re-enable setuid security fixes for 4525062 and 4525053
+
+dyld-46.2 (Inca8K1046)
+<rdar://problem/4551683> Adobe CS2 no longer launches
+<rdar://problem/4536652> Load dyld above 4GB for x86-64
+
+dyld-46.1 (Inca8K1040)
+rdar://problem/4538177 dyld does not slide on x86_64
+
+dyld-46 (Inca...)
+re-enable x86_64
+
+
+dyld-45.3 (SUSecurity )
+<rdar://problem/4607244> *SecUpd: Chardonnay* don't write warning to stderr for setuid binaries
+<rdar://problem/4607243> *SecUpd: Tiger* don't write warning to stderr for setuid binaries
+
+dyld-45.2 (SUSecurity )
+<rdar://problem/4525062> *SecUpd: Chardonnay* SureSec si#187 remove all DYLD_ env vars for setuid binaries
+<rdar://problem/4148690> *SecUpd: Tiger* SureSec si#187 remove all DYLD_ env vars for setuid binaries
+<rdar://problem/4525053> *SecUpd: Chardonnay* Suresec #203: don't use $HOME with suid binaries
+<rdar://problem/4379896> *SecUpd: Tiger* Suresec #203: don't use $HOME with suid binaries
+
+
+dyld-45.1 (SUTiLondon...)
+back out <rdar://problem/4379896> Suresec #203: dyld environment with suid binaries [SUTi]
+
+
+dyld-45 (SUTiLondon...)
+<rdar://problem/4522929> sync all 10.4.x dyld trains
+<rdar://problem/4320078> dyld fix for gcc-3.3 C++ needs to get in SU
+<rdar://problem/4501854> 64-bit dlopen crashes when opening fat bundle
+<rdar://problem/4148690> SureSec si#187 linker: environment variables [SUTi]
+<rdar://problem/4379896> Suresec #203: dyld environment with suid binaries [SUTi]
+<rdar://problem/4525062> SureSec si#187 linker: environment variables [SUChard]
+<rdar://problem/4525053> Suresec #203: dyld environment with suid binaries [SUChard]
+
+dyld-44.23 (Inca8...)
+<rdar://problem/4498577> Crash using Core Image under Rosetta running InDesign CS2 w/ Magma Effects
+
+dyld-44.22 (Inca8K1030)
+<rdar://problem/4498515> Stub binding helper changes for FP args for x86-64
+
+dyld-44.21 (Inca8K1030)
+<rdar://problem/4497724> printf doesn't work for x86-64
+
+dyld-44.20 (Inca8K1029)
+<rdar://problem/4494725> isCompatibleMachO needs to know about x86-64
+
+dyld-44.19 (Inca8J1028)
+two small x86_64 fixes
+
+dyld-44.18 (Inca8J1027)
+<rdar://problem/4442283> dyld needs to support x86-64
+
+dyld-44.17 (Chardonnay8G1152)
+<rdar://problem/4381131> prebound fast stubs not ignored for flat_namespace dylibs
+
+dyld-44.16 (Chardonnay8G1141)
+<rdar://problem/4360528> Sherlock often crashes in dyld::bindLazySymbol on launch
+
+dyld-44.15 (Chardonnay8G1137)
+<rdar://problem/4356145> no apps can launch with /usr/lib/libMallocDebug.A.dylib on 8G1133
+
+dyld-44.14 (Chardonnay8F1110)
+<rdar://problem/4321820> System Integrity: changes needed for dyld
+
+dyld-44.13 (Chardonnay8F1108)
+<rdar://problem/4313830> pthread tsd entries doubly owned by DYLD and Libsystem... (Chardonnay)
+
+dyld-44.12 (Chardonnay8F1108)
+<rdar://problem/4318081> never pass shared_region_map_file_np() a zero-length region
+
+dyld-44.11 (Chardonnay8F1104)
+<rdar://problem/4303000> dyld launch code should special case if there is only one prebound image with weak exports
+
+dyld-44.10 (Chardonnay8F1100)
+<rdar://problem/4296378> dyld fails to link with Libc-391.1.13
+
+dyld-44.9 (Chardonnay8F1093)
+<rdar://problem/4212667> XCode2.1 + gcc 3.3 + C++ exception + Bundle Bug
+<rdar://problem/4278103> low disk space code path executed with 44GB free
+
+dyld-44.8 (Chardonnay8F1079)
+<rdar://problem/4215516> dyld lazy binding code should use movdqa
+
+dyld-44.7 (Chardonnay8B1072)
+<rdar://problem/4247155> fix for rosetta crashes
+
+dyld-44.6 (Chardonnay8B1072)
+<rdar://problem/4179957> Optimizing system should only progress once
+
+dyld-44.5 (Chardonnay8B1052)
+<rdar://problem/4164559> New intel stub support
+
+dyld-44.4 (Chardonnay8B1051)
+<rdar://problem/4178195> Leopard 9A14: Finder crashes burning a CD
+<rdar://problem/4186248> dyld lazy binding code needs to save/restore all possible register parameters
+<rdar://problem/4172797> use new libstdc++-static
+
+dyld-44.3 (Chardonnay8B1051)
+<rdar://problem/4189498> dyld should recognize byte-swapped Mach-O files
+<rdar://problem/4194105> dyld should only update prebound external relocations if they change
+
+dyld-44.2 (SUTiDenver8F10) [Mac OS X 10.4.3]
+<rdar://problem/4189935> Tiger breaks NSCreateObjectFileImageFromMemory with fat Mach-O
+<rdar://problem/4139432> dyld does not load libraries correctly if matching install_name in /usr/lib
+<rdar://problem/4153431> CrashTracer: ..269 crashes at com.adobe.Acrobat.framework: RunAcrobat + 424
+
+dyld-44.1 (Chardonnay)
+<rdar://problem/4132378> __attribute__ ((regparm (3), stdcall)) doesn't work for inter-image calls
+<rdar://problem/4111112> dyld should automatically set DYLD_SHARED_REGION to avoid
+
+dyld-44 (Chardonnay)
+<rdar://problem/4170213> merge SUTiCambridge dyld and Karma dyld into Chardonnay
+
+
+dyld-43.1 (SUTiCambridge8C20)  [Mac OS X 10.4.2]
+Update open source APSL headers
+<rdar://problem/4120834> update_prebinding should gracefully handle low disk space
+<rdar://problem/4108674> prebinding should not change n_value of .obj_class_name symbols
+<rdar://problem/4057081> dyld gets into infinite loop with dlsym if dylib dependencies contain loops
+<rdar://problem/4072295> FilesBuster crashed in dyld
+<rdar://problem/4104022> DYLD_ROOT_PATH crashes program if any component does not start with /
+<rdar://problem/4104027> dyld writes past end of buffer when checking environment variables
+<rdar://problem/4106921> dyld_image_removing notification never sent
+<rdar://problem/4121907> ANN: DR020
+
+
+dyld-43 (Tiger8A428)  [Mac OS X 10.4.0]
+rdar://problem/4067311 PACE protected Mach-O apps crash under Tiger 8a420
+
+
+dyld-42 (Tiger8A420)
+rdar://problem/4058724 FileMaker JDBC extension does not work in Tiger
+
+
+dyld-41 (Tiger8A417)
+rdar://problem/4047633 Adobe Photoshop CS2: Scripting Save for Web runs out of memory unexpectedly when compared to 10.3.8.
+
+
+dyld-40 (Tiger8A413)
+rdar://problem/4047391 dyld no longer follow dependent libraries using dlopen
+
+
+dyld-39 (Tiger8A406)
+rdar://problem/4034570 DT P1: MATLAB R14sp2 does not run on Tiger
+rdar://problem/4028274 DT P1: GLSLShowpieces crashes when built and run
+
+
+dyld-38 (Tiger8A402)
+rdar://problem/3820219 Tiger + MOTU Digital Performer + hit play = Digital Performer crashes
+rdar://problem/3978682 If an excutable & a framework with the same base name are in the same folder, you get a dyld error if you use full path
+rdar://problem/3987135 MATLAB unresolved symbol __XEditResPutWidgetInfo on Tiger
+rdar://problem/4027813 dlsym man page documents unsupported RTDL_SELF
+
+
+dyld-37 (Tiger8A399)
+rdar://problem/4001668 Safari hang inside CFBundleDYLDGetSymbolByNameWithSearch in Flash plug-in upon opening www.espn.com
+rdar://problem/3853454 dyld needs to call sys_icache_invalidate() after instruction fix-ups
+rdar://problem/3984074 Soldier of Fortune II crashes at start of gameplay on Tiger8A36
+rdar://problem/4008399 Malicious user can set Tiger dyld fallback paths in setuid process
+rdar://problem/4021002 Aliens vs Predator II with latest update does not run
+
+
+dyld-36 (Tiger8A393)
+rdar://problem/3970385 [Tiger] 8A323: Aliens VS Predator 2 Freezes On Launch
+rdar://problem/3839120 _dyld_get_image_header_containing_address returning NULL when it shouldn't
+rdar://problem/3925105 update_prebinding crashes on /usr/lib/libnetsnmptrapd.5.dylib
+
+
+dyld-35 (Tiger8A384)
+rdar://problem/3984074 Soldier of Fortune II crashes at start of gameplay on Tiger8A367
+rdar://problem/4003637 Typo blocks support of -init for 64-bits
+rdar://problem/4003891 improve mmap() failure error msg
+
+
+dyld-34 (Tiger8A381)
+rdar://problem/3976215 dlopen() should look for a library with matching name and architecture  
+rdar://problem/3978682  executable and dylibs can be confused
+rdar://problem/3819111 dlopen() ignores LD_LIBRARY_PATH        
+rdar://problem/3956709 Insufficient documentation for dlopen   
+
+
+dyld-33 (Tiger8A379)
+rdar://problem/3941826 8A340: Tron 2.0 does not launch 
+rdar://problem/3848965 James Bond 007 Nightfire fails to launch        
+rdar://problem/3947513 No One Lives Forever 2 crashes on Quit on Tiger8A347
+rdar://problem/3779999 Spyhunter crashes upon launch on Tiger8A244     
+
+
+dyld-32 (Tiger8A367)
+rdar://problem/3974486 PowerMail launch fails: weak linking of library but not symbols 
+rdar://problem/3974797 can update_prebinding only complain about stuff I actually have installed?
+rdar://problem/3979715 synchronizing attribute name with section name  
+
+
+dyld-31 (Tiger8A362)
+rdar://problem/3958479 Third party "crash reporter" app backtraces have no symbols for our libraries/APIs
+rdar://problem/3966025 add DYLD_INTERPOSE macro to an apple internal header
+rdar://problem/3968283 For interposing support section-by-type and section-by-name     
+
+
+dyld-30 (Tiger8A357)
+rdar://problem/3947090  objc runtime / two-level namespace crash when using new interposing libMallocDebug or libgmalloc
+
+
+dyld-29 (Tiger8A356)
+rdar://problem/3960729  update_prebinding needs to fflush() every output line
+rdar://problem/3960657  Why are my crashreporter logs all useless?
+
+
+dyld-28 (Tiger8A354)
+rdar://problem/3510780 _dyld_get_image_header_containing_address man page is wrong
+rdar://problem/3798074 STD: dlclose() does not unload bundles  
+rdar://problem/3882857 dyld no longer finds framework file if not in Framework hierarchy
+rdar://problem/3898206 dlopen() does not support library searching as linkage at launch does
+rdar://problem/3921479 dyld(1) should not document unimplemented env vars      
+rdar://problem/3935714 Support RTLD_NODELETE   
+rdar://problem/3942919 can't use _debug libSystem      
+
+
+dyld-27 (Tiger8A350)
+rdar://problem/3902088  update_prebinding needs to provide progress information
+
+
+dyld-26 (Tiger8A348)
+rdar://problem/3943033  hang upon boot, permissions and startup thrash
+
+
+dyld-25 (Tiger8A347)
+rdar://problem/3916220  Main executable unmapped 
+rdar://problem/3812732  Microsoft Error Reporting crashes on Tiger  
+rdar://problem/3943349  dyld project should install mach-o/dyld_debug.h
+rdar://problem/3943546  mach-o/dyld_debug.h should be deprecated
+rdar://problem/3933738  use getsectdatafromheader_64
+
+
+dyld-24 (Tiger8A345)
+rdar://problem/3941688  update_prebinding needs a --dry-run option
+
+
+dyld-23
+rdar://problem/3799069  Need coalescing across dylibs
+rdar://problem/3859973  problem with weaklink using darwine
+rdar://problem/3938167  dyld does not work with XLF generated binaries and provided libraries
+rdar://problem/3935377  STD: dyld needs to include sys/time.h and sys/types.h
+rdar://problem/3930361  STD: dyld must create a stub for ___fegetfltrounds
+rdar://problem/3934712 STD:VSX: more dlfcn.h namespace issues
+
+
+dyld-22.5 (Tiger8A340)
+rdar://problem/3788633 MatLab 7.0 fails to launch on Tiger8A246        
+rdar://problem/3919674 prebound flat-namespace libraries are bound wrong
+
+
+dyld-22.4
+rdar://problem/3915914  make update_prebinding more robust
+
+
+dyld-22.3 (Tiger8A333)
+rdar://problem/3920720  dyld missing symbols because Xcode not add -fvisibility=hidden
+
+
+dyld-22.2 (Tiger8A330)
+rdar://problem/3909873  Transmit.app crashes with symbol not found
+
+
+dyld-22.1
+rdar://problem/3908248  Crash in apps when launched from MallocDebug (BlockMove symbol not found if DYLD_FORCE_FLAT_NAMESPACE is set)
+
+
+dyld-22 (Tiger8A325)
+rdar://problem/3903866  reduce LINKEDIT page usage by better use of two-level hints
+rdar://problem/3884004 Libraries can be half-baked if an error occurs during their first use   
+rdar://problem/3899047 interposing doesn't work on 8A317 with dyld-21  
+rdar://problem/3514720 Adobe bundle kernel panics system       
+
+
+dyld-21 (Tiger8A322)
+rdar://problem/3745562 Support two-level interposing with insert libraries (malloc-debug)
+rdar://problem/3892061 8A316: Selecting any application in Finder in the column view crashes finder
+rdar://problem/3894540 DYLD_PRINT_SEGMENTS no longer works on 8A317    
+
+
+dyld-20 (Tiger8A317)
+rdar://problem/32957877        Support @loader_path in dylib commands
+rdar://problem/33837173        need SPI to set fallback symbol lookup
+rdar://problem/33891778        dyld (__DATA,__dyld) function pointers should drift as little as possible
+Fix issue with new prebinding overwriting symlinks
+
+
+dyld-19 (Tiger8A315)
+rdar://problem/3823664 dyld reports corrupt executable
+rdar://problem/3847571 dyld submission number should be embedded in dyld
+rdar://problem/3865141 dyld_all_image_infos should contain bit that says if process is using the shared region
+rdar://problem/3884103 dyld needs to use -msoft-float for ppc64
+rdar://problem/3886337 PPC_RELOC_PB_LA_PTR not recognized by ppc64 
+Clean up/document dyld-gdb interface
+
+
+dyld-18.3 (prebinding sideworld build)
+prebinding enhancements
+
+dyld-18.2 (Tiger8A306)
+rdar://problem/3782982 Fix for Macromedia apps (Flash 7.2)
+
+dyld-18.1
+rdar://problem/3864644 DVD player crash (loading memory based bundle)
+
+dyld-18 (Tiger8A303)
+rdar://problem/3866877 STD:VSX dlsym() faults when passed a bad handle.
+rdar://problem/3862043 typo in dyld function name
+rdar://problem/3857000 dyld should limit its exported symbols
+rdar://problem/3835208 want better error message for incompatible libraries
+dyld now built with dead-code-stripping
+better launch performance when hundreds of libraries are used
+more bug fixes in update_prebinding in dyld
+
+
+dyld-17.1 (Tiger8A301)
+rdar://problem/3672757 initial implementation of update_prebinding in dyld
+rdar://problem/3847376 dyld does not slide itself properly (partial fix)
+rdar://problem/3843028 STD: make dlfcn.h posix compliant
+rdar://problem/3856182 STD: add includes
+rdar://problem/3782982 infrastructure work on compatibility for Macromedia apps
+Other 64-bit tweaks
+
+
+dyld-16.1 (Tiger8A296)
+rdar://problem/3768530 dyld should adopt shared_region_map_file_np() 
+
+
+dyld-15 (Gordian 64-bit side world build only)
+rdar://problem/3834744 64-bit dyld needs to handle mh->cputype != host_info cputype
+Other 64-bit clean ups
+
+
+dyld-14 (Tiger8A280)
+rdar://problem/3811777 Deadlock in dyld code, seen in Merlin and Mail
+rdar://problem/3793075 Update to fix: DVD Player crashes at launch with disc in drive
+rdar://problem/3830560 Don't let gcc-3.5 optimize away send_event
+rdar://problem/3826169 Update dlfcn.h header to Apple header and acknowledge Peter and Jorge
+rdar://problem/3793861 Update dlopen(3) man page to reflect new implementation
+rdar://problem/3559013 libdyld.a needs to build for ppc64      
+Added DYLD_PRINT_OPTS
+Added DYLD_PRINT_ENV
+Deprecated 10 APIs
+
+
+dyld-13 (Gordian 64-bit side world build only)
+rdar://problem/3560664 Add ppc64 support
+rdar://problem/3819144 Opening PDF in Safari crashes 
+rdar://problem/3793861 Update dlopen man pages
+rdar://problem/3765271 Build with gcc-3.5 
+rdar://problem/3762685 Make own prototype for task_self_trap() 
+rdar://problem/3799467 Mozilla tries to open a dylib using a bundle API
+rdar://problem/3812263 Add dyld SPI so Shark can interpose lazy pointer lookup
+Added emacs major-mode and tab-width directives
+
+
+dyld-12.4 (Tiger8A271)
+tweak so dyld can use libc.a built with long double support
+
+
+dyld-12.3 (no-build)
+rdar://problem/3765271 switch dyld to build with gcc-3.5
+
+
+dyld-12.2 (Tiger8A265)
+rdar://problem/3793075 DVD Player crashes at launch with disc in drive
+
+
+dyld-12.1 (Tiger8A255)
+rdar://problem/3749360 a flat lookup needs to search everywhere and not short-circuit to own image 
+
+
+dyld-12 (Tiger8A231)
+rdar://problem/3751226 make dyld thread safe (libdyld.a should come from new dyld project)
+rdar://problem/3654650 integrate dlopen() and friends into dyld
+
+
+dyld-11.3 (Tiger8A225)
+rdar://problem/3751226 NSAddImage() with leaf name doesn't use fallback path
+
+
+dyld-11.1 (Tiger8A223)
+rdar://problem/3749251 NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED implies NSADDIMAGE_OPTION_RETURN_ON_ERROR" 
+
+
+dyld-11 (Tiger8A220)
+rdar://problem/3684168 prevent DYLD_LIBRARY_PATH from causing circular reference when two dylib have same leaf name 
+rdar://problem/3698212 implement _dyld_launched_prebound()
+rdar://problem/3696924 suppport frameworks without symlink to current version
+rdar://problem/3692136 Support DYLD_PRINT_LIBRARIES_POST_LAUNCH
+rdar://problem/3685517 make find-image-for-address faster via caching
+rdar://problem/3661976 -force_flat_namespace should disable prebinding
+rdar://problem/3702311 make dyld's __TEXT read-only
+rdar://problem/3669059 do cpu sub-type checking on thin files
+rdar://problem/3696002 Support C++ vague linkage that resolves internally
+rdar://problem/3725847 run initializers in inserted libraries
+rdar://problem/3731063 pass arc/argv to initializers
+rdar://problem/3731100 don't write on __dyld section unless necessary
+rdar://problem/3731633 use mmap() instead of map_fd()
+rdar://problem/3676934 don't double read first page of images, use pread()
+rdar://problem/3725372 ignore environment variables for setuid binaries
+
+
+dyld-10.2 (Tiger8A157)
+rdar://problem/3668765 Macromedia apps don't launch
+
+
+dyld-10.1 (Tiger8A156)
+rdar://problem/3691952 Fix-n-continue broke in Objective-C
+
+
+dyld-10 (Tiger8A148)
+rdar://problem/3686995 implement dyld_call_module_initializers_for_dylib and do parameter sanity checking of module parameters
+rdar://problem/3674139 Make @executable_path work when main executable is a symlink
+rdar://problem/3688719 Support CW built binaries built with -data_before
+
+
+dyld-9
+rdar://problem/3682744 GoLive crash (NSIsSymbolDefinedWithHint should try harder)
+rdar://problem/3660691 iTunes crash with partial plugin
+rdar://problem/3684167 DYLD_IMAGE_SUFFIX broke
+rdar://problem/3672670 Fix uninitialized variable in objc hook
+
+
+dyld-8 (Tiger8A144)
+rdar://problem/3680627 handle weaklib when prebound
+rdar://problem/3672670 new hook for objc 
+
+
+dyld-7 (Tiger8A141)
+rdar://problem/3669059 Support cpu-sub-type selection
+rdar://problem/3675131 allow text relocations
+rdar://problem/3675614 fix lazy pointer usage in termination routines
+rdar://problem/3673658 Allow NSUnLinkModule to be called with NULL
+
+
+dyld-6 (Tiger8A139)
+rdar://problem/3649313 clean up <mach-o/dyld.h>
+rdar://problem/3661976 support MH_FORCE_FLAT
+rdar://problem/3659666 DYLD_FORCE_FLAT_NAMESPACE should disable prebinding
+Better error reporting
+Faster flat namespace lookups
+Better implementation of NSLinkEditError
+
+
+dyld-5 (Tiger8A135)
+rdar://problem/3665738 fix binding of private_extern within multi-module libs
+rdar://problem/3667763 use hints supplied in APIs
+Set error_string for CrashReporter
+Better error message when library can't be found
+Properly use ZeroLink bundle notifier
+
+
+dyld-4 (Tiger8A133)
+rdar://problem/3663433 allmemory shows 8000 pages are missing
+
+
+dyld-3 
+rdar://problem/3659408 Proper searching in umbrellas
+rdar://problem/3657040 Better error messages when symbols not found
+rdar://problem/3657197 Add ~/Library/Frameworks to fallback path
+Properly use DYLD_IMAG_SUFFIX
+Initial CrashReporter support
+
+
+dyld-2 (Tiger8A132)
+Support: NSNameOfSymbol, NSModuleForSymbol, NSLibraryNameForModule, and NSMakePrivateModulePublic
+Add more functionality to DYLD_IGNORE_PREBINDING environment variable
+
+
+dyld-1
+Initial submission of dyld rewrite.
index 60c2527b8ee9a1628db1046e24a0a328d697e0cd..679d267865a95cafad013ea58568d6f456145ec0 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Aug 28, 2008
+.Dd Nov 7, 2011
 .Os
 .Dt DLOPEN 3
 .Sh NAME
@@ -123,15 +123,18 @@ searches for a compatible Mach-O file in the directories specified by a set of e
 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. 
+are LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, and DYLD_FALLBACK_LIBRARY_PATH, but if the path specified
+is formatted like a framework, then DYLD_FRAMEWORK_PATH and DYLD_FALLBACK_FRAMEWORK_PATH are
+used instead.
+The non-fallback variables have no default value. The default value of DYLD_FALLBACK_LIBRARY_PATH
+is $HOME/lib:/usr/local/lib:/usr/lib, and DYLD_FALLBACK_FRAMEWORK_PATH is 
+$HOME/Library/Frameworks:/Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks. 
 .Fn dlopen 
 searches the directories specified in the environment variables in the order they are listed. 
 .Pp
 When 
 .Fa path
-doesn't contain a slash character (i.e. it is just a leaf name), 
+doesn't contain a slash character (i.e. it is just a leaf name and therefore not a framework), 
 .Fn dlopen
 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.
@@ -149,7 +152,8 @@ $DYLD_LIBRARY_PATH (with leaf name from
 .Pp
 Note: There are no configuration files to control dlopen searching.  
 .Pp
-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. 
+Note: If the main executable is a set[ug]id binary or codesigned with entitlements, 
+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
index 21650208c07feb210f1dadfbf2232bdaeb094063..504873ce1a416ac08347dcebcc455fbd7c98d759 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 45;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -13,6 +13,7 @@
                        buildPhases = (
                                F908135111D3ED9000626CC1 /* usr|include|mach-o */,
                                F908137011D3FB5000626CC1 /* usr|include */,
+                               F9C69EFC14EC8AB8009CAE2E /* usr|local|include */,
                                F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
                                F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
                                F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */; };
                F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */; };
                F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */; };
-               F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9B0912811F11D3400096D49 /* dsc_slider.cpp */; };
-               F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9B0913811F11DAB00096D49 /* dsc_slider.h */; };
                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
+               F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */ = {isa = PBXBuildFile; fileRef = F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */; };
                F9CE307A1208F1B50098B590 /* dsc_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CE30781208F1B50098B590 /* dsc_extractor.cpp */; };
                F9CE307B1208F1C60098B590 /* dsc_extractor.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9CE30791208F1B50098B590 /* dsc_extractor.h */; };
+               F9D1001814D8D13D00099D91 /* dsc_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CE30781208F1B50098B590 /* dsc_extractor.cpp */; };
+               F9D1001D14D8D19500099D91 /* dsc_iterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */; };
                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */; };
+               F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */ = {isa = PBXBuildFile; fileRef = F9D49CCB1458B95200F86ADD /* start_glue.s */; };
                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 */; };
                        remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
                        remoteInfo = libdsc;
                };
+               F9D1004614D8D91100099D91 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9D1001114D8D0BA00099D91;
+                       remoteInfo = dsc_extractor;
+               };
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                        name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */ = {
+               F9C69EFC14EC8AB8009CAE2E /* usr|local|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "usr/local/include/mach-o";
+                       dstPath = /usr/local/include;
                        dstSubfolderSpec = 0;
                        files = (
-                               F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */,
+                               F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */,
                        );
-                       name = "usr|local|include|mach-o";
+                       name = "usr|local|include";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
                F9AB709D0BA75730002F6068 /* dyldLibSystemInterface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyldLibSystemInterface.h; path = src/dyldLibSystemInterface.h; sourceTree = "<group>"; };
                F9AC7E930B7BB67700FEB38B /* version.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = BUILT_PRODUCTS_DIR; };
                F9B01E3D0739ABDE00CF981B /* dyld.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld.exp; path = src/dyld.exp; sourceTree = SOURCE_ROOT; };
-               F9B0912311F11D1600096D49 /* libdsc_slider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdsc_slider.a; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9B0912811F11D3400096D49 /* dsc_slider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_slider.cpp; sourceTree = "<group>"; };
-               F9B0913811F11DAB00096D49 /* dsc_slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_slider.h; sourceTree = "<group>"; };
+               F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-shared-cache.h"; path = "include/objc-shared-cache.h"; sourceTree = "<group>"; };
                F9CE30781208F1B50098B590 /* dsc_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_extractor.cpp; sourceTree = "<group>"; };
                F9CE30791208F1B50098B590 /* dsc_extractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_extractor.h; sourceTree = "<group>"; };
+               F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = dsc_extractor.bundle; 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>"; };
+               F9D49CCB1458B95200F86ADD /* start_glue.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = start_glue.s; path = src/start_glue.s; 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 /* libdyld.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdyld.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F9D1001014D8D0BA00099D91 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */,
                                F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */,
                                F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */,
-                               F9B0912811F11D3400096D49 /* dsc_slider.cpp */,
-                               F9B0913811F11DAB00096D49 /* dsc_slider.h */,
                                F9CE30781208F1B50098B590 /* dsc_extractor.cpp */,
                                F9CE30791208F1B50098B590 /* dsc_extractor.h */,
                                F99B8E620FEC11B400701838 /* dyld_shared_cache_util.cpp */,
                                F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
                                F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
                                F99B8E670FEC121100701838 /* dyld_shared_cache_util */,
-                               F9B0912311F11D1600096D49 /* libdsc_slider.a */,
+                               F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                F9ED4CCD0630A7F100DF4E74 /* dyldLock.h */,
                                F9ED4CCE0630A7F100DF4E74 /* dyldNew.cpp */,
                                F9ED4CCF0630A7F100DF4E74 /* dyldStartup.s */,
+                               F9D49CCB1458B95200F86ADD /* start_glue.s */,
                                F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */,
                                F9ED4CD00630A7F100DF4E74 /* glue.c */,
                                F9ED4CD10630A7F100DF4E74 /* ImageLoader.cpp */,
                                F939F219078F1A2100AC144F /* dyld_debug.h */,
                                F9ED4CEA0630A80600DF4E74 /* dyld.h */,
                                F99EE6AE06B48D4200BF1992 /* dlfcn.h */,
+                               F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */,
                        );
                        name = include;
                        sourceTree = "<group>";
                };
 /* End PBXGroup section */
 
+/* Begin PBXHeadersBuildPhase section */
+               F9D1000E14D8D0BA00099D91 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
 /* Begin PBXNativeTarget section */
                F93937310A94FAF700070A07 /* update_dyld_shared_cache */ = {
                        isa = PBXNativeTarget;
                        dependencies = (
                                F99B8EA00FEC195800701838 /* PBXTargetDependency */,
                                F9CE330B120F40EA0098B590 /* PBXTargetDependency */,
+                               F9D1004714D8D91100099D91 /* PBXTargetDependency */,
                        );
                        name = update_dyld_shared_cache;
                        productName = update_dyld_shared_cache;
                        productReference = F99B8E670FEC121100701838 /* dyld_shared_cache_util */;
                        productType = "com.apple.product-type.tool";
                };
-               F9B0912211F11D1600096D49 /* libdsc_slider */ = {
+               F9D1001114D8D0BA00099D91 /* dsc_extractor */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */;
+                       buildConfigurationList = F9D1001714D8D0F100099D91 /* Build configuration list for PBXNativeTarget "dsc_extractor" */;
                        buildPhases = (
-                               F9B0912011F11D1600096D49 /* Sources */,
-                               F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */,
+                               F9D1000E14D8D0BA00099D91 /* Headers */,
+                               F9D1000F14D8D0BA00099D91 /* Sources */,
+                               F9D1001014D8D0BA00099D91 /* Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
-                       name = libdsc_slider;
-                       productName = libdsc_slider;
-                       productReference = F9B0912311F11D1600096D49 /* libdsc_slider.a */;
-                       productType = "com.apple.product-type.library.static";
+                       name = dsc_extractor;
+                       productName = dsc_extractor;
+                       productReference = F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */;
+                       productType = "com.apple.product-type.library.dynamic";
                };
                F9ED4C970630A76000DF4E74 /* dyld */ = {
                        isa = PBXNativeTarget;
 /* Begin PBXProject section */
                F9ED4C8B0630A72300DF4E74 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0440;
+                       };
                        buildConfigurationList = F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */;
-                       compatibilityVersion = "Xcode 3.1";
+                       compatibilityVersion = "Xcode 3.2";
                        developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
                                F9F2A5580F7AEE9800B7C9EB /* libdsc */,
                                F99B8E550FEC10F600701838 /* dyld_shared_cache_util */,
-                               F9B0912211F11D1600096D49 /* libdsc_slider */,
+                               F9D1001114D8D0BA00099D91 /* dsc_extractor */,
                        );
                };
 /* End PBXProject section */
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n     # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n     # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n";
+                       shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n     # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n     # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n\nif [ -n \"${RC_PURPLE}\" ]\nthen\n    mkdir -p \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/lib\"\n    mv \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/local/lib/dsc_extractor.bundle\" \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle\"\nfi";
                        showEnvVarsInLog = 0;
                };
                F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               F9B0912011F11D1600096D49 /* Sources */ = {
+               F9D1000F14D8D0BA00099D91 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */,
+                               F9D1001814D8D13D00099D91 /* dsc_extractor.cpp in Sources */,
+                               F9D1001D14D8D19500099D91 /* dsc_iterator.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
                                F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */,
                                F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */,
+                               F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        target = F9F2A5580F7AEE9800B7C9EB /* libdsc */;
                        targetProxy = F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */;
                };
+               F9D1004714D8D91100099D91 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9D1001114D8D0BA00099D91 /* dsc_extractor */;
+                       targetProxy = F9D1004614D8D91100099D91 /* PBXContainerItemProxy */;
+               };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F9ED4C970630A76000DF4E74 /* dyld */;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                INSTALLHDRS_COPY_PHASE = YES;
                                PRODUCT_NAME = libdyld;
                                ZERO_LINK = NO;
                F93937350A94FB2900070A07 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_DYNAMIC_NO_PIC = YES;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_THREADSAFE_STATICS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               PREBINDING = NO;
+                               HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
                                PRODUCT_NAME = update_dyld_shared_cache;
                                VALID_ARCHS = "x86_64 i386";
                        };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = x86_64;
+                               CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                GCC_OPTIMIZATION_LEVEL = s;
                                GCC_THREADSAFE_STATICS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
                                INSTALL_PATH = "$(INSTALL_LOCATION)/usr/$(LOCAL)/bin";
                                LOCAL = "$(LOCAL_$(RC_TARGET_CONFIG))";
                                LOCAL_iPhone = local;
-                               PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
                                STRIP_INSTALLED_PRODUCT = YES;
                                STRIP_STYLE = debugging;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld_shared_cache_util;
                        };
                        name = Debug;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld_shared_cache_util;
                                SKIP_INSTALL = NO;
                        };
                        name = Release;
                };
-               F9B0912411F11D1700096D49 /* Debug */ = {
+               F9D1001314D8D0BB00099D91 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                COPY_PHASE_STRIP = NO;
+                               DYLIB_COMPATIBILITY_VERSION = "";
+                               DYLIB_CURRENT_VERSION = "";
+                               EXECUTABLE_EXTENSION = bundle;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
-                               GCC_MODEL_TUNING = G5;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
-                               PRODUCT_NAME = libdsc_slider;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+                               MACH_O_TYPE = mh_bundle;
+                               OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+                               PRODUCT_NAME = dsc_extractor;
                        };
                        name = Debug;
                };
-               F9B0912511F11D1700096D49 /* Release */ = {
+               F9D1001414D8D0BB00099D91 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               COPY_PHASE_STRIP = NO;
+                               COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
-                               INSTALLHDRS_COPY_PHASE = YES;
-                               INSTALL_PATH = /usr/local/lib;
-                               PRODUCT_NAME = dsc_slider;
+                               DYLIB_COMPATIBILITY_VERSION = "";
+                               DYLIB_CURRENT_VERSION = "";
+                               EXECUTABLE_EXTENSION = bundle;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+                               MACH_O_TYPE = mh_bundle;
+                               OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+                               PRODUCT_NAME = dsc_extractor;
                                ZERO_LINK = NO;
                        };
                        name = Release;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               ARCHS = (
-                                       i386,
-                                       x86_64,
-                               );
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
                                BASE_ADDRESS_armv4t = 0x2fe00000;
                                BASE_ADDRESS_armv5 = 0x2fe00000;
                                BASE_ADDRESS_armv6 = 0x2fe00000;
                                BASE_ADDRESS_armv7 = 0x2fe00000;
+                               BASE_ADDRESS_armv7f = 0x2fe00000;
+                               BASE_ADDRESS_armv7k = 0x2fe00000;
                                BASE_ADDRESS_i386 = 0x8fe00000;
                                BASE_ADDRESS_ppc = 0x8fe00000;
                                BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+                               CLANG_CXX_LIBRARY = "libc++";
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
                                        "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
-                                       "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
                F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = (
-                                       x86_64,
-                                       i386,
-                               );
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                BASE_ADDRESS_armv4t = 0x2fe00000;
                                BASE_ADDRESS_armv5 = 0x2fe00000;
                                BASE_ADDRESS_armv6 = 0x2fe00000;
                                BASE_ADDRESS_armv7 = 0x2fe00000;
+                               BASE_ADDRESS_armv7f = 0x2fe00000;
+                               BASE_ADDRESS_armv7k = 0x2fe00000;
                                BASE_ADDRESS_i386 = 0x8fe00000;
                                BASE_ADDRESS_ppc = 0x8fe00000;
                                BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+                               CLANG_CXX_LIBRARY = "libc++";
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
                                        "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
-                                       "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
                                INSTALL_PATH = /usr/lib/system;
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                INSTALL_PATH = /usr/lib/system;
                                OTHER_LDFLAGS = (
                                        "-nodefaultlibs",
-                                       "-lSystem",
+                                       "-Wl,-upward-lSystem",
                                        "-umbrella",
                                        System,
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                SEPARATE_STRIP = YES;
                                STRIP_INSTALLED_PRODUCT = YES;
                F9D8C7EA087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               CLANG_CXX_LIBRARY = "compiler-default";
                        };
                        name = Debug;
                };
                F9D8C7EC087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               CLANG_CXX_LIBRARY = "compiler-default";
                        };
                        name = Release;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
                                PRODUCT_NAME = dsc;
                        };
                        name = Debug;
                                COPY_PHASE_STRIP = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_ENABLE_OBJC_EXCEPTIONS = NO;
                                GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_MODEL_TUNING = G5;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */ = {
+               F9D1001714D8D0F100099D91 /* Build configuration list for PBXNativeTarget "dsc_extractor" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               F9B0912411F11D1700096D49 /* Debug */,
-                               F9B0912511F11D1700096D49 /* Release */,
+                               F9D1001314D8D0BB00099D91 /* Debug */,
+                               F9D1001414D8D0BB00099D91 /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
index 04137accc65e3f5b351b1a78900a343bd49bbf7e..eaadf6488b8c5e32e81b0f7ea05799c23f11093d 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
 /*
  * 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__
+#if __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
index b33c23197c2ac77d5b905fa1a4312e8fe6341318..9464fb818e339e7ed794da295709bb919f02664d 100644 (file)
@@ -178,6 +178,41 @@ extern const char* dyld_image_path_containing_address(const void* addr);
 
 
 
+
+//
+// This is finds the SDK version a binary was built against.
+// Returns zero on error, or if SDK version could not be determined.
+//
+// Exists in Mac OS X 10.8 and later 
+extern uint32_t dyld_get_sdk_version(const struct mach_header* mh);
+
+
+//
+// This is finds the SDK version the main executable was built against.
+// Returns zero on error, or if SDK version could not be determined.
+//
+// Exists in Mac OS X 10.8 and later 
+extern uint32_t dyld_get_program_sdk_version();
+
+
+//
+// This is finds the min OS version a binary was built to run on.
+// Returns zero on error, or if no min OS recorded in binary.
+//
+// Exists in Mac OS X 10.8 and later 
+extern uint32_t dyld_get_min_os_version(const struct mach_header* mh);
+
+
+//
+// This is finds the min OS version the main executable was built to run on.
+// Returns zero on error, or if no min OS recorded in binary.
+//
+// Exists in Mac OS X 10.8 and later 
+extern uint32_t dyld_get_program_min_os_version();
+
+
+
+
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
 //
 // Returns if any OS dylib has overridden its copy in the shared cache
diff --git a/include/objc-shared-cache.h b/include/objc-shared-cache.h
new file mode 100644 (file)
index 0000000..b7db57d
--- /dev/null
@@ -0,0 +1,1363 @@
+/* 
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+Portions derived from:
+
+--------------------------------------------------------------------
+lookup8.c, by Bob Jenkins, January 4 1997, Public Domain.
+hash(), hash2(), hash3, and mix() are externally useful functions.
+Routines to test the hash are included if SELF_TEST is defined.
+You can use this free for any purpose.  It has no warranty.
+--------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+perfect.c: code to generate code for a hash for perfect hashing.
+(c) Bob Jenkins, September 1996, December 1999
+You may use this code in any way you wish, and it is free.  No warranty.
+I hereby place this in the public domain.
+Source is http://burtleburtle.net/bob/c/perfect.c
+------------------------------------------------------------------------------
+*/
+
+/*
+ * objc-selopt.h
+ * Interface between libobjc and dyld 
+ * for selector uniquing in the dyld shared cache.
+ *
+ * When building the shared cache, dyld locates all selectors and selector 
+ * references in the cached images. It builds a perfect hash table out of 
+ * them and writes the table into the shared cache copy of libobjc.
+ * libobjc then uses that table as the builtin selector list.
+ *
+ * Versioning
+ * The table has a version number. dyld and objc can both ignore the table 
+ * if the other used the wrong version number.
+ *
+ * Completeness
+ * Not all libraries are in the shared cache. Libraries that are in the 
+ * shared cache and were optimized are specially marked. Libraries on 
+ * disk never include those marks.
+ *
+ * Coherency
+ * Libraries optimized in the shared cache can be replaced by unoptimized 
+ * copies from disk when loaded. The copy from disk is not marked and will 
+ * be fixed up by libobjc. The shared cache copy is still mapped into the 
+ * process, so the table can point to cstring data in that library's part 
+ * of the shared cache without trouble.
+ * 
+ * Atomicity
+ * dyld writes the table itself last. If dyld marks some metadata as 
+ * updated but then fails to write a table for some reason, libobjc 
+ * fixes up all metadata as if it were not marked.
+ */
+
+#ifndef _OBJC_SELOPT_H
+#define _OBJC_SELOPT_H
+
+/*
+  DO NOT INCLUDE ANY objc HEADERS HERE
+  dyld USES THIS FILE AND CANNOT SEE THEM
+*/
+#include <stdint.h>
+#include <stdlib.h>
+#ifdef SELOPT_WRITE
+#include <ext/hash_map>
+#endif
+/*
+  DO NOT INCLUDE ANY objc HEADERS HERE
+  dyld USES THIS FILE AND CANNOT SEE THEM
+*/
+
+#ifndef STATIC_ASSERT
+#   define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
+#   define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
+#   define _STATIC_ASSERT3(x, line)                                     \
+        typedef struct {                                                \
+            int _static_assert[(x) ? 0 : -1];                           \
+        } _static_assert_ ## line __attribute__((unavailable)) 
+#endif
+
+#define SELOPT_DEBUG 0
+
+#define S32(x) x = little_endian ? OSSwapHostToLittleInt32(x) : OSSwapHostToBigInt32(x)
+#define S64(x) x = little_endian ? OSSwapHostToLittleInt64(x) : OSSwapHostToBigInt64(x)
+
+namespace objc_opt {
+
+typedef int32_t objc_stringhash_offset_t;
+typedef uint8_t objc_stringhash_check_t;
+
+#ifdef SELOPT_WRITE
+
+// Perfect hash code is at the end of this file.
+
+struct perfect_hash {
+    uint32_t capacity;
+    uint32_t occupied;
+    uint32_t shift;
+    uint32_t mask;
+    uint64_t salt;
+    
+    uint32_t scramble[256];
+    uint8_t *tab;  // count == mask+1; free with delete[]
+    
+    perfect_hash() : tab(0) { }
+    
+    ~perfect_hash() { if (tab) delete[] tab; }
+};
+
+struct eqstr {
+    bool operator()(const char* s1, const char* s2) const {
+        return strcmp(s1, s2) == 0;
+    }
+};
+
+// cstring => cstring's vmaddress
+// (used for selector names and class names)
+typedef __gnu_cxx::hash_map<const char *, uint64_t, __gnu_cxx::hash<const char *>, eqstr> string_map;
+
+// class name => (class vmaddress, header_info vmaddress)
+typedef __gnu_cxx::hash_multimap<const char *, std::pair<uint64_t, uint64_t>, __gnu_cxx::hash<const char *>, eqstr> class_map;
+
+static perfect_hash make_perfect(const string_map& strings);
+
+#endif
+
+static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level);
+
+// Precomputed perfect hash table of strings.
+// Base class for precomputed selector table and class table.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_stringhash_t {
+    uint32_t capacity;
+    uint32_t occupied;
+    uint32_t shift;
+    uint32_t mask;
+    uint32_t zero;
+    uint32_t unused; // alignment pad
+    uint64_t salt;
+    
+    uint32_t scramble[256];
+    uint8_t tab[0];                   /* tab[mask+1] (always power-of-2) */
+    // uint8_t checkbytes[capacity];  /* check byte for each string */
+    // int32_t offsets[capacity];     /* offsets from &capacity to cstrings */
+
+    objc_stringhash_check_t *checkbytes() { return (objc_stringhash_check_t *)&tab[mask+1]; }
+    const objc_stringhash_check_t *checkbytes() const { return (const objc_stringhash_check_t *)&tab[mask+1]; }
+
+    objc_stringhash_offset_t *offsets() { return (objc_stringhash_offset_t *)&checkbytes()[capacity]; }
+    const objc_stringhash_offset_t *offsets() const { return (const objc_stringhash_offset_t *)&checkbytes()[capacity]; }
+
+    uint32_t hash(const char *key) const
+    {
+        uint64_t val = lookup8((uint8_t*)key, strlen(key), salt);
+        uint32_t index = (uint32_t)(val>>shift) ^ scramble[tab[val&mask]];
+        return index;
+    }
+
+    // The check bytes areused to reject strings that aren't in the table
+    // without paging in the table's cstring data. This checkbyte calculation 
+    // catches 4785/4815 rejects when launching Safari; a perfect checkbyte 
+    // would catch 4796/4815.
+    objc_stringhash_check_t checkbyte(const char *key) const
+    {
+        return 
+            ((key[0] & 0x7) << 5)
+            |
+            (strlen(key) & 0x1f);
+    }
+
+#define INDEX_NOT_FOUND (~(uint32_t)0)
+
+    uint32_t getIndex(const char *key) const 
+    {
+        uint32_t h = hash(key);
+
+        // Use check byte to reject without paging in the table's cstrings
+        objc_stringhash_check_t h_check = checkbytes()[h];
+        objc_stringhash_check_t key_check = checkbyte(key);
+        bool check_fail = (h_check != key_check);
+#if ! SELOPT_DEBUG
+        if (check_fail) return INDEX_NOT_FOUND;
+#endif
+
+        const char *result = (const char *)this + offsets()[h];
+        if (0 != strcmp(key, result)) return INDEX_NOT_FOUND;
+
+#if SELOPT_DEBUG
+        if (check_fail) abort();
+#endif
+
+        return h;
+    }
+
+#ifdef SELOPT_WRITE
+
+    size_t size() 
+    {
+        return sizeof(objc_stringhash_t) 
+            + mask+1 
+            + capacity * sizeof(objc_stringhash_check_t) 
+            + capacity * sizeof(objc_stringhash_offset_t);
+    }
+
+    void byteswap(bool little_endian) 
+    {
+        // tab and checkbytes are arrays of bytes, no swap needed
+        for (uint32_t i = 0; i < 256; i++) {
+            S32(scramble[i]);
+        }
+        objc_stringhash_offset_t *o = offsets();
+        for (uint32_t i = 0; i < capacity; i++) {
+            S32(o[i]);
+        }
+        
+        S32(capacity);
+        S32(occupied);
+        S32(shift);
+        S32(mask);
+        S32(zero);
+        S64(salt);
+    }
+
+    const char *write(uint64_t base, size_t remaining, string_map& strings)
+    {        
+        if (sizeof(objc_stringhash_t) > remaining) {
+            return "selector section too small (metadata not optimized)";
+        }
+
+        if (strings.size() == 0) {
+            bzero(this, sizeof(objc_stringhash_t));
+            return NULL;
+        }
+        
+        perfect_hash phash = make_perfect(strings);
+        if (phash.capacity == 0) {
+            return "perfect hash failed (metadata not optimized)";
+        }
+
+        // Set header
+        capacity = phash.capacity;
+        occupied = phash.occupied;
+        shift = phash.shift;
+        mask = phash.mask;
+        zero = 0;
+        unused = 0;
+        salt = phash.salt;
+
+        if (size() > remaining) {
+            return "selector section too small (metadata not optimized)";
+        }
+        
+        // Set hash data
+        for (uint32_t i = 0; i < 256; i++) {
+            scramble[i] = phash.scramble[i];
+        }
+        for (uint32_t i = 0; i < phash.mask+1; i++) {
+            tab[i] = phash.tab[i];
+        }
+        
+        // Set offsets to ""
+        for (uint32_t i = 0; i < phash.capacity; i++) {
+            offsets()[i] = 
+                (objc_stringhash_offset_t)offsetof(objc_stringhash_t, zero);
+        }
+        // Set checkbytes to 0
+        for (uint32_t i = 0; i < phash.capacity; i++) {
+            checkbytes()[i] = 0;
+        }
+        
+        // Set real string offsets and checkbytes
+#       define SHIFT (64 - 8*sizeof(objc_stringhash_offset_t))
+        string_map::const_iterator s;
+        for (s = strings.begin(); s != strings.end(); ++s) {
+            int64_t offset = s->second - base;
+            if ((offset<<SHIFT)>>SHIFT != offset) {
+                return "selector offset too big (metadata not optimized)";
+            }
+
+            uint32_t h = hash(s->first);
+            offsets()[h] = (objc_stringhash_offset_t)offset;
+            checkbytes()[h] = checkbyte(s->first);
+        }
+#       undef SHIFT
+        
+        return NULL;
+    }
+
+// SELOPT_WRITE
+#endif
+};
+
+
+// Precomputed selector table.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_selopt_t : objc_stringhash_t { 
+    const char *get(const char *key) const 
+    {
+        uint32_t h = getIndex(key);
+        if (h == INDEX_NOT_FOUND) return NULL;
+        
+        return (const char *)this + offsets()[h];
+    }
+};
+
+// Precomputed class list.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change these structures.
+
+struct objc_classheader_t {
+    objc_stringhash_offset_t clsOffset;
+    objc_stringhash_offset_t hiOffset;
+
+    // For duplicate class names:
+    // clsOffset = count<<1 | 1
+    // duplicated classes are duplicateOffsets[hiOffset..hiOffset+count-1]
+    bool isDuplicate() const { return clsOffset & 1; }
+    uint32_t duplicateCount() const { return clsOffset >> 1; }
+    uint32_t duplicateIndex() const { return hiOffset; }
+};
+
+
+struct objc_clsopt_t : objc_stringhash_t {
+    // ...objc_stringhash_t fields...
+    // objc_classheader_t classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
+    // uint32_t duplicateCount;
+    // objc_classheader_t duplicateOffsets[duplicatedClasses];
+
+    objc_classheader_t *classOffsets() { return (objc_classheader_t *)&offsets()[capacity]; }
+    const objc_classheader_t *classOffsets() const { return (const objc_classheader_t *)&offsets()[capacity]; }
+    
+    uint32_t& duplicateCount() { return *(uint32_t *)&classOffsets()[capacity]; }
+    const uint32_t& duplicateCount() const { return *(const uint32_t *)&classOffsets()[capacity]; }
+
+    objc_classheader_t *duplicateOffsets() { return (objc_classheader_t *)(&duplicateCount()+1); }
+    const objc_classheader_t *duplicateOffsets() const { return (const objc_classheader_t *)(&duplicateCount()+1); }
+
+    // 0/NULL/NULL: not found
+    // 1/ptr/ptr: found exactly one
+    // n/NULL/NULL:  found N - use getClassesAndHeaders() instead
+    uint32_t getClassAndHeader(const char *key, void*& cls, void*& hi) const 
+    {
+        uint32_t h = getIndex(key);
+        if (h == INDEX_NOT_FOUND) { 
+            cls = NULL;
+            hi = NULL;
+            return 0;
+        }
+
+        const objc_classheader_t& clshi = classOffsets()[h];
+        if (! clshi.isDuplicate()) {
+            // class appears in exactly one header
+            cls = (void *)((const char *)this + clshi.clsOffset);
+            hi  = (void *)((const char *)this + clshi.hiOffset);
+            return 1;
+        } 
+        else {
+            // class appears in more than one header - use getClassesAndHeaders
+            cls = NULL;
+            hi = NULL;
+            return clshi.duplicateCount();
+        }
+    }
+
+    void getClassesAndHeaders(const char *key, void **cls, void **hi) const 
+    {
+        uint32_t h = getIndex(key);
+        if (h == INDEX_NOT_FOUND) return;
+
+        const objc_classheader_t& clshi = classOffsets()[h];
+        if (! clshi.isDuplicate()) {
+            // class appears in exactly one header
+            cls[0] = (void *)((const char *)this + clshi.clsOffset);
+            hi[0]  = (void *)((const char *)this + clshi.hiOffset);
+        } 
+        else {
+            // class appears in more than one header
+            uint32_t count = clshi.duplicateCount();
+            const objc_classheader_t *list = 
+                &duplicateOffsets()[clshi.duplicateIndex()];
+            for (uint32_t i = 0; i < count; i++) {
+                cls[i] = (void *)((const char *)this + list[i].clsOffset);
+                hi[i]  = (void *)((const char *)this + list[i].hiOffset);
+            }
+        }
+    }
+
+#ifdef SELOPT_WRITE
+
+    size_t size() 
+    {
+        return
+            objc_stringhash_t::size()
+            + capacity * sizeof(objc_classheader_t)
+            + sizeof(duplicateCount())
+            + duplicateCount() * sizeof(objc_classheader_t);
+    }
+
+    void byteswap(bool little_endian) 
+    {
+        objc_classheader_t *o;
+        
+        o = classOffsets();
+        for (uint32_t i = 0; i < capacity; i++) {
+            S32(o[i].clsOffset);
+            S32(o[i].hiOffset);
+        }
+
+        o = duplicateOffsets();
+        for (uint32_t i = 0; i < duplicateCount(); i++) {
+            S32(o[i].clsOffset);
+            S32(o[i].hiOffset);
+        }
+
+        S32(duplicateCount());
+
+        objc_stringhash_t::byteswap(little_endian);
+    }
+    
+    const char *write(uint64_t base, size_t remaining, 
+                      string_map& strings, class_map& classes, bool verbose)
+    {
+        const char *err;
+        err = objc_stringhash_t::write(base, remaining, strings);
+        if (err) return err;
+
+        if (size() > remaining) {
+            return "selector section too small (metadata not optimized)";
+        }
+
+        // Set class offsets to &zero
+        objc_stringhash_offset_t zeroOffset = 
+            (objc_stringhash_offset_t)offsetof(objc_stringhash_t, zero);
+        for (uint32_t i = 0; i < capacity; i++) {
+            classOffsets()[i].clsOffset = zeroOffset;
+            classOffsets()[i].hiOffset = zeroOffset;
+        }
+        
+        // Set real class offsets
+#       define SHIFT (64 - 8*sizeof(objc_stringhash_offset_t))
+        class_map::const_iterator c;
+        for (c = classes.begin(); c != classes.end(); ++c) {
+            uint32_t h = getIndex(c->first);
+            if (h == INDEX_NOT_FOUND) {
+                return "class list busted (metadata not optimized)";
+            }
+
+            if (classOffsets()[h].clsOffset != zeroOffset) {
+                // already did this class
+                continue;
+            }
+
+            uint32_t count = classes.count(c->first);
+            if (count == 1) {
+                // only one class with this name
+
+                int64_t coff = c->second.first - base;
+                int64_t hoff = c->second.second - base;
+                if ((coff<<SHIFT)>>SHIFT != coff) {
+                    return "class offset too big (metadata not optimized)";
+                }
+                if ((hoff<<SHIFT)>>SHIFT != hoff) {
+                    return "header offset too big (metadata not optimized)";
+                }
+
+                classOffsets()[h].clsOffset = (objc_stringhash_offset_t)coff;
+                classOffsets()[h].hiOffset  = (objc_stringhash_offset_t)hoff;
+            }
+            else {
+                // class name has duplicates - write them all now
+                if (verbose) {
+                    fprintf(stderr, "update_dyld_shared_cache: %u duplicates of Objective-C class %s\n", count, c->first);
+                }
+
+                uint32_t dest = duplicateCount();
+                duplicateCount() += count;                
+                if (size() > remaining) {
+                    return "selector section too small (metadata not optimized)";
+                }
+
+                // classOffsets() instead contains count and array index
+                classOffsets()[h].clsOffset = count*2 + 1;
+                classOffsets()[h].hiOffset = dest;
+
+                std::pair<class_map::const_iterator, class_map::const_iterator>
+                    duplicates = classes.equal_range(c->first);
+                class_map::const_iterator dup;
+                for (dup = duplicates.first; dup != duplicates.second; ++dup) {
+                    int64_t coff = dup->second.first - base;
+                    int64_t hoff = dup->second.second - base;
+                    if ((coff<<SHIFT)>>SHIFT != coff) {
+                        return "class offset too big (metadata not optimized)";
+                    }
+                    if ((hoff<<SHIFT)>>SHIFT != hoff) {
+                        return "header offset too big (metadata not optimized)";
+                    }
+                    
+                    duplicateOffsets()[dest].clsOffset = (objc_stringhash_offset_t)coff;
+                    duplicateOffsets()[dest].hiOffset  = (objc_stringhash_offset_t)hoff;
+                    dest++;
+                }
+            } 
+        }
+#       undef SHIFT
+        
+        return NULL;
+    }
+
+// SELOPT_WRITE
+#endif
+};
+
+// Precomputed image list.
+struct objc_headeropt_t;
+
+// Precomputed class list.
+struct objc_clsopt_t;
+
+// Edit objc-sel-table.s if you change this value.
+enum { VERSION = 12 };
+
+// Top-level optimization structure.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_opt_t {
+    uint32_t version;
+    int32_t selopt_offset;
+    int32_t headeropt_offset;
+    int32_t clsopt_offset;
+
+    const objc_selopt_t* selopt() const { 
+        if (selopt_offset == 0) return NULL;
+        return (objc_selopt_t *)((uint8_t *)this + selopt_offset);
+    }
+    objc_selopt_t* selopt() { 
+        if (selopt_offset == 0) return NULL;
+        return (objc_selopt_t *)((uint8_t *)this + selopt_offset);
+    }
+
+    struct objc_headeropt_t* headeropt() const { 
+        if (headeropt_offset == 0) return NULL;
+        return (struct objc_headeropt_t *)((uint8_t *)this + headeropt_offset);
+    }
+
+    struct objc_clsopt_t* clsopt() const { 
+        if (clsopt_offset == 0) return NULL;
+        return (objc_clsopt_t *)((uint8_t *)this + clsopt_offset);
+    }
+};
+
+// sizeof(objc_opt_t) must be pointer-aligned
+STATIC_ASSERT(sizeof(objc_opt_t) % sizeof(void*) == 0);
+
+// Initializer for empty opt of type uint32_t[].
+#define X8(x) x, x, x, x, x, x, x, x
+#define X64(x) X8(x), X8(x), X8(x), X8(x), X8(x), X8(x), X8(x), X8(x)
+#define X256(x) X64(x), X64(x), X64(x), X64(x)
+#define OPT_INITIALIZER {                                           \
+        /* objc_opt_t */                                            \
+        objc_opt::VERSION, 16, 0, 0,                                \
+        /* objc_selopt_t */                                         \
+        4, 4, 63, 3, 0, 0, 0,0, X256(0), 0, 0, 16, 16, 16, 16       \
+        /* no objc_headeropt_t */                                   \
+        /* no objc_clsopt_t */                                      \
+}
+
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 64-bit values reversibly.
+mix() takes 48 machine instructions, but only 24 cycles on a superscalar
+  machine (like Intel's new MMX architecture).  It requires 4 64-bit
+  registers for 4::2 parallelism.
+All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of
+  (a,b,c), and all deltas of bottom bits were tested.  All deltas were
+  tested both on random keys and on keys that were nearly all zero.
+  These deltas all cause every bit of c to change between 1/3 and 2/3
+  of the time (well, only 113/400 to 287/400 of the time for some
+  2-bit delta).  These deltas all cause at least 80 bits to change
+  among (a,b,c) when the mix is run either forward or backward (yes it
+  is reversible).
+This implies that a hash using mix64 has no funnels.  There may be
+  characteristics with 3-bit deltas or bigger, I didn't test for
+  those.
+--------------------------------------------------------------------
+*/
+#define mix64(a,b,c) \
+{ \
+  a -= b; a -= c; a ^= (c>>43); \
+  b -= c; b -= a; b ^= (a<<9); \
+  c -= a; c -= b; c ^= (b>>8); \
+  a -= b; a -= c; a ^= (c>>38); \
+  b -= c; b -= a; b ^= (a<<23); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>35); \
+  b -= c; b -= a; b ^= (a<<49); \
+  c -= a; c -= b; c ^= (b>>11); \
+  a -= b; a -= c; a ^= (c>>12); \
+  b -= c; b -= a; b ^= (a<<18); \
+  c -= a; c -= b; c ^= (b>>22); \
+}
+
+/*
+--------------------------------------------------------------------
+hash() -- hash a variable-length key into a 64-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  level : can be any 8-byte value
+Returns a 64-bit value.  Every bit of the key affects every bit of
+the return value.  No funnels.  Every 1-bit and 2-bit delta achieves
+avalanche.  About 41+5len instructions.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 64 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
+
+By Bob Jenkins, Jan 4 1997.  bob_jenkins@burtleburtle.net.  You may
+use this code any way you wish, private, educational, or commercial,
+but I would appreciate if you give me credit.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^^64
+is acceptable.  Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level)
+// uint8_t *k;        /* the key */
+// uint64_t  length;   /* the length of the key */
+// uint64_t  level;    /* the previous hash, or an arbitrary value */
+{
+  uint64_t a,b,c;
+  size_t len;
+
+  /* Set up the internal state */
+  len = length;
+  a = b = level;                         /* the previous hash value */
+  c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */
+
+  /*---------------------------------------- handle most of the key */
+  while (len >= 24)
+  {
+    a += (k[0]        +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24)
+     +((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56));
+    b += (k[8]        +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24)
+     +((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56));
+    c += (k[16]       +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24)
+     +((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56));
+    mix64(a,b,c);
+    k += 24; len -= 24;
+  }
+
+  /*------------------------------------- handle the last 23 bytes */
+  c += length;
+  switch(len)              /* all the case statements fall through */
+  {
+  case 23: c+=((uint64_t)k[22]<<56);
+  case 22: c+=((uint64_t)k[21]<<48);
+  case 21: c+=((uint64_t)k[20]<<40);
+  case 20: c+=((uint64_t)k[19]<<32);
+  case 19: c+=((uint64_t)k[18]<<24);
+  case 18: c+=((uint64_t)k[17]<<16);
+  case 17: c+=((uint64_t)k[16]<<8);
+    /* the first byte of c is reserved for the length */
+  case 16: b+=((uint64_t)k[15]<<56);
+  case 15: b+=((uint64_t)k[14]<<48);
+  case 14: b+=((uint64_t)k[13]<<40);
+  case 13: b+=((uint64_t)k[12]<<32);
+  case 12: b+=((uint64_t)k[11]<<24);
+  case 11: b+=((uint64_t)k[10]<<16);
+  case 10: b+=((uint64_t)k[ 9]<<8);
+  case  9: b+=((uint64_t)k[ 8]);
+  case  8: a+=((uint64_t)k[ 7]<<56);
+  case  7: a+=((uint64_t)k[ 6]<<48);
+  case  6: a+=((uint64_t)k[ 5]<<40);
+  case  5: a+=((uint64_t)k[ 4]<<32);
+  case  4: a+=((uint64_t)k[ 3]<<24);
+  case  3: a+=((uint64_t)k[ 2]<<16);
+  case  2: a+=((uint64_t)k[ 1]<<8);
+  case  1: a+=((uint64_t)k[ 0]);
+    /* case 0: nothing left to add */
+  }
+  mix64(a,b,c);
+  /*-------------------------------------------- report the result */
+  return c;
+}
+
+
+#ifdef SELOPT_WRITE
+
+/*
+------------------------------------------------------------------------------
+This generates a minimal perfect hash function.  That means, given a
+set of n keys, this determines a hash function that maps each of
+those keys into a value in 0..n-1 with no collisions.
+
+The perfect hash function first uses a normal hash function on the key
+to determine (a,b) such that the pair (a,b) is distinct for all
+keys, then it computes a^scramble[tab[b]] to get the final perfect hash.
+tab[] is an array of 1-byte values and scramble[] is a 256-term array of 
+2-byte or 4-byte values.  If there are n keys, the length of tab[] is a 
+power of two between n/3 and n.
+
+I found the idea of computing distinct (a,b) values in "Practical minimal 
+perfect hash functions for large databases", Fox, Heath, Chen, and Daoud, 
+Communications of the ACM, January 1992.  They found the idea in Chichelli 
+(CACM Jan 1980).  Beyond that, our methods differ.
+
+The key is hashed to a pair (a,b) where a in 0..*alen*-1 and b in
+0..*blen*-1.  A fast hash function determines both a and b
+simultaneously.  Any decent hash function is likely to produce
+hashes so that (a,b) is distinct for all pairs.  I try the hash
+using different values of *salt* until all pairs are distinct.
+
+The final hash is (a XOR scramble[tab[b]]).  *scramble* is a
+predetermined mapping of 0..255 into 0..smax-1.  *tab* is an
+array that we fill in in such a way as to make the hash perfect.
+
+First we fill in all values of *tab* that are used by more than one
+key.  We try all possible values for each position until one works.
+
+This leaves m unmapped keys and m values that something could hash to.
+If you treat unmapped keys as lefthand nodes and unused hash values
+as righthand nodes, and draw a line connecting each key to each hash
+value it could map to, you get a bipartite graph.  We attempt to
+find a perfect matching in this graph.  If we succeed, we have
+determined a perfect hash for the whole set of keys.
+
+*scramble* is used because (a^tab[i]) clusters keys around *a*.
+------------------------------------------------------------------------------
+*/
+
+typedef uint64_t  ub8;
+#define UB8MAXVAL 0xffffffffffffffffLL
+#define UB8BITS 64
+typedef uint32_t  ub4;
+#define UB4MAXVAL 0xffffffff
+#define UB4BITS 32
+typedef uint16_t  ub2;
+#define UB2MAXVAL 0xffff
+#define UB2BITS 16
+typedef uint8_t ub1;
+#define UB1MAXVAL 0xff
+#define UB1BITS 8
+
+#define TRUE  1
+#define FALSE 0
+
+#define SCRAMBLE_LEN 256 // ((ub4)1<<16)                    /* length of *scramble* */
+#define RETRY_INITKEY 2048  /* number of times to try to find distinct (a,b) */
+#define RETRY_PERFECT 4     /* number of times to try to make a perfect hash */
+
+
+/* representation of a key */
+struct key
+{
+  ub1        *name_k;                                      /* the actual key */
+  ub4         len_k;                         /* the length of the actual key */
+  ub4         hash_k;                 /* the initial hash value for this key */
+/* beyond this point is mapping-dependent */
+  ub4         a_k;                            /* a, of the key maps to (a,b) */
+  ub4         b_k;                            /* b, of the key maps to (a,b) */
+  struct key *nextb_k;                               /* next key with this b */
+};
+typedef  struct key  key;
+
+/* things indexed by b of original (a,b) pair */
+struct bstuff
+{
+  ub2  val_b;                                        /* hash=a^tabb[b].val_b */
+  key *list_b;                   /* tabb[i].list_b is list of keys with b==i */
+  ub4  listlen_b;                                        /* length of list_b */
+  ub4  water_b;           /* high watermark of who has visited this map node */
+};
+typedef  struct bstuff  bstuff;
+
+/* things indexed by final hash value */
+struct hstuff
+{
+  key *key_h;                   /* tabh[i].key_h is the key with a hash of i */
+};
+typedef  struct hstuff hstuff;
+
+/* things indexed by queue position */
+struct qstuff
+{
+  bstuff *b_q;                        /* b that currently occupies this hash */
+  ub4     parent_q;     /* queue position of parent that could use this hash */
+  ub2     newval_q;      /* what to change parent tab[b] to to use this hash */
+  ub2     oldval_q;                              /* original value of tab[b] */
+};
+typedef  struct qstuff  qstuff;
+
+
+/*
+------------------------------------------------------------------------------
+Find the mapping that will produce a perfect hash
+------------------------------------------------------------------------------
+*/
+
+/* return the ceiling of the log (base 2) of val */
+static ub4  log2u(ub4 val)
+{
+  ub4 i;
+  for (i=0; ((ub4)1<<i) < val; ++i)
+    ;
+  return i;
+}
+
+/* compute p(x), where p is a permutation of 0..(1<<nbits)-1 */
+/* permute(0)=0.  This is intended and useful. */
+static ub4  permute(ub4 x, ub4 nbits)
+// ub4 x;                                       /* input, a value in some range */
+// ub4 nbits;                                 /* input, number of bits in range */
+{
+  int i;
+  int mask   = ((ub4)1<<nbits)-1;                                /* all ones */
+  int const2 = 1+nbits/2;
+  int const3 = 1+nbits/3;
+  int const4 = 1+nbits/4;
+  int const5 = 1+nbits/5;
+  for (i=0; i<20; ++i)
+  {
+    x = (x+(x<<const2)) & mask; 
+    x = (x^(x>>const3));
+    x = (x+(x<<const4)) & mask;
+    x = (x^(x>>const5));
+  }
+  return x;
+}
+
+/* initialize scramble[] with distinct random values in 0..smax-1 */
+static void scrambleinit(ub4 *scramble, ub4 smax)
+// ub4      *scramble;                            /* hash is a^scramble[tab[b]] */
+// ub4       smax;                    /* scramble values should be in 0..smax-1 */
+{
+  ub4 i;
+
+  /* fill scramble[] with distinct random integers in 0..smax-1 */
+  for (i=0; i<SCRAMBLE_LEN; ++i)
+  {
+    scramble[i] = permute(i, log2u(smax));
+  }
+}
+
+
+/* 
+ * put keys in tabb according to key->b_k
+ * check if the initial hash might work 
+ */
+static int inittab(bstuff *tabb, ub4 blen, key *keys, ub4 nkeys, int complete)
+// bstuff   *tabb;                     /* output, list of keys with b for (a,b) */
+// ub4       blen;                                            /* length of tabb */
+// key      *keys;                               /* list of keys already hashed */
+// int       complete;        /* TRUE means to complete init despite collisions */
+{
+  int  nocollision = TRUE;
+  ub4 i;
+
+  memset((void *)tabb, 0, (size_t)(sizeof(bstuff)*blen));
+
+  /* Two keys with the same (a,b) guarantees a collision */
+  for (i = 0; i < nkeys; i++) {
+    key *mykey = keys+i;
+    key *otherkey;
+
+    for (otherkey=tabb[mykey->b_k].list_b; 
+        otherkey; 
+        otherkey=otherkey->nextb_k)
+    {
+      if (mykey->a_k == otherkey->a_k)
+      {
+        nocollision = FALSE;
+       if (!complete)
+         return FALSE;
+      }
+    }
+    ++tabb[mykey->b_k].listlen_b;
+    mykey->nextb_k = tabb[mykey->b_k].list_b;
+    tabb[mykey->b_k].list_b = mykey;
+  }
+
+  /* no two keys have the same (a,b) pair */
+  return nocollision;
+}
+
+
+/* Do the initial hash for normal mode (use lookup and checksum) */
+static void initnorm(key *keys, ub4 nkeys, ub4 alen, ub4 blen, ub4 smax, ub8 salt)
+// key      *keys;                                          /* list of all keys */
+// ub4       alen;                    /* (a,b) has a in 0..alen-1, a power of 2 */
+// ub4       blen;                    /* (a,b) has b in 0..blen-1, a power of 2 */
+// ub4       smax;                   /* maximum range of computable hash values */
+// ub4       salt;                     /* used to initialize the hash function */
+// gencode  *final;                          /* output, code for the final hash */
+{
+  ub4 loga = log2u(alen);                            /* log based 2 of blen */
+  ub4 i;
+  for (i = 0; i < nkeys; i++) {
+    key *mykey = keys+i;
+    ub8 hash = lookup8(mykey->name_k, mykey->len_k, salt);
+    mykey->a_k = (loga > 0) ? hash>>(UB8BITS-loga) : 0;
+    mykey->b_k = (blen > 1) ? hash&(blen-1) : 0;
+  }
+}
+
+
+/* Try to apply an augmenting list */
+static int apply(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 *scramble, ub4 tail, int rollback)
+// bstuff *tabb;
+// hstuff *tabh;
+// qstuff *tabq;
+// ub4     blen;
+// ub4    *scramble;
+// ub4     tail;
+// int     rollback;          /* FALSE applies augmenting path, TRUE rolls back */
+{
+  ub4     hash;
+  key    *mykey;
+  bstuff *pb;
+  ub4     child;
+  ub4     parent;
+  ub4     stabb;                                         /* scramble[tab[b]] */
+
+  /* walk from child to parent */
+  for (child=tail-1; child; child=parent)
+  {
+    parent = tabq[child].parent_q;                    /* find child's parent */
+    pb     = tabq[parent].b_q;             /* find parent's list of siblings */
+
+    /* erase old hash values */
+    stabb = scramble[pb->val_b];
+    for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+    {
+      hash = mykey->a_k^stabb;
+      if (mykey == tabh[hash].key_h)
+      {                            /* erase hash for all of child's siblings */
+       tabh[hash].key_h = (key *)0;
+      }
+    }
+
+    /* change pb->val_b, which will change the hashes of all parent siblings */
+    pb->val_b = (rollback ? tabq[child].oldval_q : tabq[child].newval_q);
+
+    /* set new hash values */
+    stabb = scramble[pb->val_b];
+    for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+    {
+      hash = mykey->a_k^stabb;
+      if (rollback)
+      {
+       if (parent == 0) continue;                  /* root never had a hash */
+      }
+      else if (tabh[hash].key_h)
+      {
+       /* very rare: roll back any changes */
+        apply(tabb, tabh, tabq, blen, scramble, tail, TRUE);
+       return FALSE;                                  /* failure, collision */
+      }
+      tabh[hash].key_h = mykey;
+    }
+  }
+  return TRUE;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+augment(): Add item to the mapping.
+
+Construct a spanning tree of *b*s with *item* as root, where each
+parent can have all its hashes changed (by some new val_b) with 
+at most one collision, and each child is the b of that collision.
+
+I got this from Tarjan's "Data Structures and Network Algorithms".  The
+path from *item* to a *b* that can be remapped with no collision is 
+an "augmenting path".  Change values of tab[b] along the path so that 
+the unmapped key gets mapped and the unused hash value gets used.
+
+Assuming 1 key per b, if m out of n hash values are still unused, 
+you should expect the transitive closure to cover n/m nodes before 
+an unused node is found.  Sum(i=1..n)(n/i) is about nlogn, so expect
+this approach to take about nlogn time to map all single-key b's.
+-------------------------------------------------------------------------------
+*/
+static int augment(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 *scramble, ub4 smax, bstuff *item, ub4 nkeys, 
+                  ub4 highwater)
+// bstuff   *tabb;                                        /* stuff indexed by b */
+// hstuff   *tabh;  /* which key is associated with which hash, indexed by hash */
+// qstuff   *tabq;            /* queue of *b* values, this is the spanning tree */
+// ub4       blen;                                            /* length of tabb */
+// ub4      *scramble;                      /* final hash is a^scramble[tab[b]] */
+// ub4       smax;                                 /* highest value in scramble */
+// bstuff   *item;                           /* &tabb[b] for the b to be mapped */
+// ub4       nkeys;                         /* final hash must be in 0..nkeys-1 */
+// ub4       highwater;        /* a value higher than any now in tabb[].water_b */
+{
+  ub4  q;                      /* current position walking through the queue */
+  ub4  tail;              /* tail of the queue.  0 is the head of the queue. */
+  ub4  limit=UB1MAXVAL+1;
+  ub4  highhash = smax;
+
+  /* initialize the root of the spanning tree */
+  tabq[0].b_q = item;
+  tail = 1;
+
+  /* construct the spanning tree by walking the queue, add children to tail */
+  for (q=0; q<tail; ++q)
+  {
+    bstuff *myb = tabq[q].b_q;                        /* the b for this node */
+    ub4     i;                              /* possible value for myb->val_b */
+
+    if (q == 1) 
+      break;                                  /* don't do transitive closure */
+
+    for (i=0; i<limit; ++i)
+    {
+      bstuff *childb = (bstuff *)0;             /* the b that this i maps to */
+      key    *mykey;                       /* for walking through myb's keys */
+
+      for (mykey = myb->list_b; mykey; mykey=mykey->nextb_k)
+      {
+       key    *childkey;
+       ub4 hash = mykey->a_k^scramble[i];
+
+       if (hash >= highhash) break;                        /* out of bounds */
+       childkey = tabh[hash].key_h;
+
+       if (childkey)
+       {
+         bstuff *hitb = &tabb[childkey->b_k];
+
+         if (childb)
+         {
+           if (childb != hitb) break;            /* hit at most one child b */
+         }
+         else
+         {
+           childb = hitb;                        /* remember this as childb */
+           if (childb->water_b == highwater) break;     /* already explored */
+         }
+       }
+      }
+      if (mykey) continue;             /* myb with i has multiple collisions */
+
+      /* add childb to the queue of reachable things */
+      if (childb) childb->water_b = highwater;
+      tabq[tail].b_q      = childb;
+      tabq[tail].newval_q = i;     /* how to make parent (myb) use this hash */
+      tabq[tail].oldval_q = myb->val_b;            /* need this for rollback */
+      tabq[tail].parent_q = q;
+      ++tail;
+
+      if (!childb)
+      {                                  /* found an *i* with no collisions? */
+       /* try to apply the augmenting path */
+       if (apply(tabb, tabh, tabq, blen, scramble, tail, FALSE))
+         return TRUE;        /* success, item was added to the perfect hash */
+
+       --tail;                    /* don't know how to handle such a child! */
+      }
+    }
+  }
+  return FALSE;
+}
+
+
+/* find a mapping that makes this a perfect hash */
+static int perfect(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 smax, ub4 *scramble, ub4 nkeys)
+{
+  ub4 maxkeys;                           /* maximum number of keys for any b */
+  ub4 i, j;
+
+#if SELOPT_DEBUG
+  fprintf(stderr, "           blen %d smax %d nkeys %d\n", blen, smax, nkeys);
+#endif
+
+  /* clear any state from previous attempts */
+  memset((void *)tabh, 0, sizeof(hstuff)*smax);
+  memset((void *)tabq, 0, sizeof(qstuff)*(blen+1));
+
+  for (maxkeys=0,i=0; i<blen; ++i) 
+    if (tabb[i].listlen_b > maxkeys) 
+      maxkeys = tabb[i].listlen_b;
+
+  /* In descending order by number of keys, map all *b*s */
+  for (j=maxkeys; j>0; --j)
+    for (i=0; i<blen; ++i)
+      if (tabb[i].listlen_b == j)
+       if (!augment(tabb, tabh, tabq, blen, scramble, smax, &tabb[i], nkeys, 
+                    i+1))
+       {
+         return FALSE;
+       }
+
+  /* Success!  We found a perfect hash of all keys into 0..nkeys-1. */
+  return TRUE;
+}
+
+
+/* guess initial values for alen and blen */
+static void initalen(ub4 *alen, ub4 *blen, ub4 smax, ub4 nkeys)
+// ub4      *alen;                                      /* output, initial alen */
+// ub4      *blen;                                      /* output, initial blen */
+// ub4      smax;    /* input, power of two greater or equal to max hash value */
+// ub4       nkeys;                              /* number of keys being hashed */
+{
+  /*
+   * Find initial *alen, *blen
+   * Initial alen and blen values were found empirically.  Some factors:
+   *
+   * If smax<256 there is no scramble, so tab[b] needs to cover 0..smax-1.
+   *
+   * alen and blen must be powers of 2 because the values in 0..alen-1 and
+   * 0..blen-1 are produced by applying a bitmask to the initial hash function.
+   *
+   * alen must be less than smax, in fact less than nkeys, because otherwise
+   * there would often be no i such that a^scramble[i] is in 0..nkeys-1 for
+   * all the *a*s associated with a given *b*, so there would be no legal
+   * value to assign to tab[b].  This only matters when we're doing a minimal
+   * perfect hash.
+   *
+   * It takes around 800 trials to find distinct (a,b) with nkey=smax*(5/8)
+   * and alen*blen = smax*smax/32.
+   *
+   * Values of blen less than smax/4 never work, and smax/2 always works.
+   *
+   * We want blen as small as possible because it is the number of bytes in
+   * the huge array we must create for the perfect hash.
+   *
+   * When nkey <= smax*(5/8), blen=smax/4 works much more often with 
+   * alen=smax/8 than with alen=smax/4.  Above smax*(5/8), blen=smax/4
+   * doesn't seem to care whether alen=smax/8 or alen=smax/4.  I think it
+   * has something to do with 5/8 = 1/8 * 5.  For example examine 80000, 
+   * 85000, and 90000 keys with different values of alen.  This only matters
+   * if we're doing a minimal perfect hash.
+   *
+   * When alen*blen <= 1<<UB4BITS, the initial hash must produce one integer.
+   * Bigger than that it must produce two integers, which increases the
+   * cost of the hash per character hashed.
+   */
+  *alen = smax;                     /* no reason to restrict alen to smax/2 */
+  *blen = ((nkeys <= smax*0.6) ? smax/16 : 
+           (nkeys <= smax*0.8) ? smax/8 : smax/4);
+  
+  if (*alen < 1) *alen = 1;
+  if (*blen < 1) *blen = 1;
+
+#if SELOPT_DEBUG
+  fprintf(stderr, "alen %d blen %d smax %d nkeys %d\n", *alen, *blen, smax, nkeys);
+#endif
+}
+
+/* 
+** Try to find a perfect hash function.  
+** Return the successful initializer for the initial hash. 
+** Return 0 if no perfect hash could be found.
+*/
+static int findhash(bstuff **tabb, ub4 *alen, ub4 *blen, ub8 *salt, 
+                    ub4 *scramble, ub4 smax, key *keys, ub4 nkeys)
+// bstuff  **tabb;           /* output, tab[] of the perfect hash, length *blen */
+// ub4      *alen;                 /* output, 0..alen-1 is range for a of (a,b) */
+// ub4      *blen;                 /* output, 0..blen-1 is range for b of (a,b) */
+// ub4      *salt;                         /* output, initializes initial hash */
+// ub4      *scramble;                      /* input, hash = a^scramble[tab[b]] */
+// ub4      smax;                           /* input, scramble[i] in 0..smax-1 */
+// key      *keys;                                       /* input, keys to hash */
+// ub4       nkeys;                       /* input, number of keys being hashed */
+{
+  ub4 bad_initkey;                       /* how many times did initkey fail? */
+  ub4 bad_perfect;                       /* how many times did perfect fail? */
+  ub4 si;                        /* trial initializer for initial hash */
+  ub4 maxalen;
+  hstuff *tabh;                       /* table of keys indexed by hash value */
+  qstuff *tabq;    /* table of stuff indexed by queue value, used by augment */
+
+  /* guess initial values for alen and blen */
+  initalen(alen, blen, smax, nkeys);
+
+  scrambleinit(scramble, smax);
+
+  maxalen = smax;
+
+  /* allocate working memory */
+  *tabb = new bstuff[*blen];
+  tabq  = new qstuff[*blen+1];
+  tabh  = new hstuff[smax];
+
+  /* Actually find the perfect hash */
+  *salt = 0;
+  bad_initkey = 0;
+  bad_perfect = 0;
+  for (si=1; ; ++si)
+  {
+    ub4 rslinit;
+    /* Try to find distinct (A,B) for all keys */
+    *salt = si * 0x9e3779b97f4a7c13LL; /* golden ratio (arbitrary value) */
+    initnorm(keys, nkeys, *alen, *blen, smax, *salt);
+    rslinit = inittab(*tabb, *blen, keys, nkeys, FALSE);
+    if (rslinit == 0)
+    {
+      /* didn't find distinct (a,b) */
+      if (++bad_initkey >= RETRY_INITKEY)
+      {
+       /* Try to put more bits in (A,B) to make distinct (A,B) more likely */
+       if (*alen < maxalen)
+       {
+         *alen *= 2;
+       } 
+       else if (*blen < smax)
+       {
+         *blen *= 2;
+         delete[] tabq;
+         delete[] *tabb;
+         *tabb  = new bstuff[*blen];
+         tabq  = new qstuff[*blen+1];
+       }
+       bad_initkey = 0;
+       bad_perfect = 0;
+      }
+      continue;                             /* two keys have same (a,b) pair */
+    }
+
+    /* Given distinct (A,B) for all keys, build a perfect hash */
+    if (!perfect(*tabb, tabh, tabq, *blen, smax, scramble, nkeys))
+    {
+      if (++bad_perfect >= RETRY_PERFECT)
+      {
+       if (*blen < smax)
+       {
+         *blen *= 2;
+         delete[] *tabb;
+         delete[] tabq;
+         *tabb  = new bstuff[*blen];
+         tabq  = new qstuff[*blen+1];
+         --si;               /* we know this salt got distinct (A,B) */
+       }
+       else
+       {
+          return 0;
+       }
+       bad_perfect = 0;
+      }
+      continue;
+    }
+    
+    break;
+  }
+
+  /* free working memory */
+  delete[] tabh;
+  delete[] tabq;
+
+  return 1;
+}
+
+/*
+------------------------------------------------------------------------------
+Input/output type routines
+------------------------------------------------------------------------------
+*/
+
+/* get the list of keys */
+static void getkeys(key **keys, ub4 *nkeys, const string_map& strings)
+{
+  key *buf = new key[strings.size()];
+  size_t i;
+  string_map::const_iterator s;
+  for (i = 0, s = strings.begin(); s != strings.end(); ++s, ++i) {
+    key *mykey = buf+i;
+    mykey->name_k = (ub1 *)s->first;
+    mykey->len_k  = (ub4)strlen(s->first);
+  }
+  *keys = buf;
+  *nkeys = strings.size();
+}
+
+
+static perfect_hash 
+make_perfect(const string_map& strings)
+{
+  ub4       nkeys;                                         /* number of keys */
+  key      *keys;                                    /* head of list of keys */
+  bstuff   *tab;                                       /* table indexed by b */
+  ub4       smax;            /* scramble[] values in 0..smax-1, a power of 2 */
+  ub4       alen;                            /* a in 0..alen-1, a power of 2 */
+  ub4       blen;                            /* b in 0..blen-1, a power of 2 */
+  ub8       salt;                       /* a parameter to the hash function */
+  ub4       scramble[SCRAMBLE_LEN];           /* used in final hash function */
+  int ok;
+  int i;
+  perfect_hash result;
+
+  /* read in the list of keywords */
+  getkeys(&keys, &nkeys, strings);
+
+  /* find the hash */
+  smax = ((ub4)1<<log2u(nkeys));
+  ok = findhash(&tab, &alen, &blen, &salt, 
+                scramble, smax, keys, nkeys);
+  if (!ok) {
+      smax = 2 * ((ub4)1<<log2u(nkeys));
+      ok = findhash(&tab, &alen, &blen, &salt, 
+                    scramble, smax, keys, nkeys);
+  }
+  if (!ok) {
+      bzero(&result, sizeof(result));
+  } else {
+      /* build the tables */
+      result.capacity = smax;
+      result.occupied = nkeys;
+      result.shift = UB8BITS - log2u(alen);
+      result.mask = blen - 1;
+      result.salt = salt;
+      
+      result.tab = new uint8_t[blen];
+      for (i = 0; i < blen; i++) {
+          result.tab[i] = tab[i].val_b;
+      }
+      for (i = 0; i < 256; i++) {
+          result.scramble[i] = scramble[i];
+      }
+  }
+
+  delete[] keys;
+  delete[] tab;
+
+  return result;
+}
+
+// SELOPT_WRITE
+#endif
+
+// namespace objc_selopt
+};
+
+#undef S32
+#undef S64
+
+#endif
index 05d64306f8a7fe3a033fb4ec7b5665dd9084b1dc..e26825d27436b5e4aa26c9e7fc1a0cca1a1d7422 100644 (file)
 //
 // Architectures
 //
-struct ppc
-{
-       typedef Pointer32<BigEndian>            P;
-       
-};
-
 struct x86
 {
        typedef Pointer32<LittleEndian>         P;
index ac882dc357d4a21dacbb5c55a25dd961a5345988..332478fa19112648dc9185bfe16b1755e5237026 100644 (file)
@@ -97,7 +97,7 @@ private:
        void                                                                            doBindDyldLazyInfo(std::vector<void*>& pointersInData);
        void                                                                            bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, 
                                                                                                                                int libraryOrdinal, int64_t addend, 
-                                                                                                                               const char* symbolName, bool lazyPointer,
+                                                                                                                               const char* symbolName, bool lazyPointer, bool weakImport,
                                                                                                                                std::vector<void*>& pointersInData);
        pint_t                                                                          resolveUndefined(const macho_nlist<P>* undefinedSymbol);
        bool                                                                            findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol);
@@ -190,7 +190,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                                fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
                        case LC_RPATH:
-                               throwf("LC_RPATH not supported in dylibs in dyld shared cache");
+                               throwf("dyld shared cache does not support LC_RPATH found in %s", layout.getFilePath());
                                break;
                        default:
                                if ( cmd->cmd() & LC_REQ_DYLD )
@@ -262,12 +262,10 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
        }
 }
 
-template <> uint8_t    Binder<ppc>::pointerRelocSize()    { return 2; }
 template <> uint8_t    Binder<x86>::pointerRelocSize()   { return 2; }
 template <> uint8_t    Binder<x86_64>::pointerRelocSize() { return 3; }
 template <> uint8_t    Binder<arm>::pointerRelocSize() { return 2; }
 
-template <> uint8_t    Binder<ppc>::pointerRelocType()    { return GENERIC_RELOC_VANILLA; }
 template <> uint8_t    Binder<x86>::pointerRelocType()   { return GENERIC_RELOC_VANILLA; }
 template <> uint8_t    Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
 template <> uint8_t    Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
@@ -363,8 +361,18 @@ void Binder<A>::setDependentBinders(const Map& map)
                                                        }
                                                }
                                        }
-                                       if ( ! found )
-                                               throwf("in %s can't find dylib %s", this->getDylibID(), path);
+                                       if ( ! found ) {
+                                               if ( cmd->cmd() == LC_LOAD_WEAK_DYLIB ) {
+                                                       BinderAndReExportFlag entry;
+                                                       entry.binder = NULL;
+                                                       entry.reExport = false;
+                                                       fDependentDylibs.push_back(entry);
+                                                       break;
+                                               }
+                                               else {
+                                                       throwf("in %s can't find dylib %s", this->getDylibID(), path);
+                                               }
+                                       }
                                }
                                break;
                }
@@ -534,7 +542,7 @@ void Binder<A>::doSetUpDyldSection()
 
 template <typename A>
 void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal, 
-                                                       int64_t addend, const char* symbolName, bool lazyPointer, std::vector<void*>& pointersInData)
+                                                       int64_t addend, const char* symbolName, bool lazyPointer, bool weakImport, std::vector<void*>& pointersInData)
 {
        //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
        const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
@@ -561,9 +569,16 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
        pint_t targetSymbolAddress;
        bool isResolverSymbol;
     Binder<A>* foundIn;
-       if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) ) 
-               throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
-
+       if ( weakImport && (binder == NULL) ) {
+               targetSymbolAddress = 0;
+               foundIn = NULL;
+               isResolverSymbol = false;
+       }
+       else {
+               if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) ) 
+                       throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
+       }
+       
        // don't bind lazy pointers to resolver stubs in shared cache
        if ( lazyPointer && isResolverSymbol ) {
         if ( foundIn == this ) {
@@ -620,6 +635,7 @@ void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
        const char* symbolName = NULL;
        int libraryOrdinal = 0;
        int64_t addend = 0;
+       bool weakImport = false;
        while ( p < end ) {
                uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
                uint8_t opcode = *p & BIND_OPCODE_MASK;
@@ -644,6 +660,7 @@ void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
                                }
                                break;
                        case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
                                symbolName = (char*)p;
                                while (*p != '\0')
                                        ++p;
@@ -657,7 +674,7 @@ void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
                                segmentOffset = read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, true, pointersInData);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, true, weakImport, pointersInData);
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_SET_TYPE_IMM:
@@ -687,6 +704,7 @@ void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
        int64_t addend = 0;
        uint32_t count;
        uint32_t skip;
+       bool weakImport = false;
        bool done = false;
        while ( !done && (p < end) ) {
                uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
@@ -712,6 +730,7 @@ void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
                                }
                                break;
                        case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
                                symbolName = (char*)p;
                                while (*p != '\0')
                                        ++p;
@@ -731,22 +750,22 @@ void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
                                segmentOffset += read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
                                segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
                                segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
                                count = read_uleb128(p, end);
                                skip = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
-                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
+                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
                                        segmentOffset += skip + sizeof(pint_t);
                                }
                                break;
index 3be3fa2eb0c7d8d7fe052062f889b902a3f79f3d..6314caacedefe3951242b56fd45dfe6b82fc7ac7 100644 (file)
@@ -52,6 +52,15 @@ struct uuid_command {
 #ifndef CPU_SUBTYPE_ARM_V7
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
+#ifndef CPU_SUBTYPE_ARM_V7F
+       #define CPU_SUBTYPE_ARM_V7F                     ((cpu_subtype_t) 10)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+       #define CPU_SUBTYPE_ARM_V7K                     ((cpu_subtype_t) 12)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+       #define CPU_SUBTYPE_ARM_V7S                     ((cpu_subtype_t) 11)
+#endif
 
 #ifndef LC_LOAD_UPWARD_DYLIB
        #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
@@ -64,6 +73,19 @@ struct uuid_command {
        #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
 #endif
 
+#ifndef LC_FUNCTION_STARTS
+       #define LC_FUNCTION_STARTS 0x26
+#endif
+
+#ifndef LC_DATA_IN_CODE
+       #define LC_DATA_IN_CODE 0x29
+#endif
+
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+       #define LC_DYLIB_CODE_SIGN_DRS 0x2B
+#endif
+
+
 
 #include "FileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -790,6 +812,20 @@ public:
         return NULL;
     }
 
+    const macho_load_command<P>* getLoadCommand(int query) const
+    {
+        const macho_load_command<P>* cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
+        uint32_t cmd_count = this->ncmds();
+        const macho_load_command<P>* cmd = cmds;
+        for (uint32_t i = 0; i < cmd_count; ++i) {
+            if ( cmd->cmd() == query ) {
+                return cmd;
+            }
+            cmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+        }
+        return NULL;
+    }
+
        typedef typename P::E           E;
 private:
        macho_header_content<P> header;
index e23cbac280dfc8214d6532bc2dff39783999b4d1..4d6583b6bb858f1a6623d3b230e45a082a73dffc 100644 (file)
@@ -364,9 +364,6 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                                        }
                                        try {
                                                switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
-                                                       case CPU_TYPE_POWERPC:
-                                                               fLayouts.push_back(new MachOLayout<ppc>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
-                                                               break;
                                                        case CPU_TYPE_I386:
                                                                fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
@@ -376,9 +373,6 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                                                        case CPU_TYPE_ARM:
                                                                fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
-                                                       case CPU_TYPE_POWERPC64:
-                                                               // ignore ppc64 slices
-                                                               break;
                                                        default:
                                                                throw "unknown slice in fat file";
                                                }
@@ -391,11 +385,7 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                }
                else {
                        try {
-                               if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
-                                       if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(mh->cputype), OSSwapBigToHostInt32(mh->cpusubtype)) ) 
-                                               fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
-                               }
-                               else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
                                        if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
@@ -407,9 +397,6 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                                        if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
-                               else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
-                                       // ignore ppc64 slices
-                               }
                                else {
                                        throw "unknown file format";
                                }
@@ -569,18 +556,11 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
 
 }
 
-template <> cpu_type_t MachOLayout<ppc>::arch()     { return CPU_TYPE_POWERPC; }
 template <> cpu_type_t MachOLayout<x86>::arch()     { return CPU_TYPE_I386; }
 template <> cpu_type_t MachOLayout<x86_64>::arch()  { return CPU_TYPE_X86_64; }
 template <> cpu_type_t MachOLayout<arm>::arch()                { return CPU_TYPE_ARM; }
 
 
-template <>
-bool MachOLayout<ppc>::isSplitSeg() const
-{
-       return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
-}
-
 template <>
 bool MachOLayout<x86>::isSplitSeg() const
 {
index 8907aad90dda84b0b8a8c4a8f13f3b69a898c385..88c4f83d0db08ef6fab0fd6fe07f1719c73f9ccc 100644 (file)
@@ -38,7 +38,6 @@
 #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 <mach-o/arm/reloc.h>
 #include <vector>
@@ -170,7 +169,6 @@ Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
        fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides();
 }
 
-template <> cpu_type_t Rebaser<ppc>::getArchitecture()    const { return CPU_TYPE_POWERPC; }
 template <> cpu_type_t Rebaser<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
 template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
 template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
@@ -536,25 +534,103 @@ void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToData
                        value64 += codeToDataDelta;
                         A::P::E::set64(*(uint64_t*)p, value64);
                        break;
-               case 3: // used only for ppc, 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;                  
+        case 5: // used by thumb2 movw
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       instruction = A::P::E::get32(*p);
+                       // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
+                       value = (instruction & 0x0000000F) + (codeToDataDelta >> 12);
+                       instruction = (instruction & 0xFFFFFFF0) | (value & 0x0000000F);
+                       A::P::E::set32(*p, instruction);
+                       break;
+        case 6: // used by ARM movw
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       instruction = A::P::E::get32(*p);
+                       // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
+                       value = ((instruction & 0x000F0000) >> 16) + (codeToDataDelta >> 12);
+                       instruction = (instruction & 0xFFF0FFFF) | ((value <<16) & 0x000F0000);
+                       A::P::E::set32(*p, instruction);
                        break;
+               case 0x10:
+               case 0x11:
+               case 0x12:
+               case 0x13:
+               case 0x14:
+               case 0x15:
+               case 0x16:
+               case 0x17:
+               case 0x18:
+               case 0x19:
+               case 0x1A:
+               case 0x1B:
+               case 0x1C:
+               case 0x1D:
+               case 0x1E:
+               case 0x1F:
+                       // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
+                       {
+                               p = (uint32_t*)mappedAddressForVMAddress(address);
+                               instruction = A::P::E::get32(*p);
+                               // extract 16-bit value from instruction
+                               uint32_t i =    ((instruction & 0x00000400) >> 10);
+                               uint32_t imm4 =  (instruction & 0x0000000F);
+                               uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+                               uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+                               uint32_t imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+                               // combine with codeToDataDelta and kind nibble
+                               uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
+                               uint32_t newTargetValue = targetValue + codeToDataDelta;
+                               // construct new bits slices
+                               uint32_t imm4_  = (newTargetValue & 0xF0000000) >> 28;
+                               uint32_t i_             = (newTargetValue & 0x08000000) >> 27;
+                               uint32_t imm3_  = (newTargetValue & 0x07000000) >> 24;
+                               uint32_t imm8_  = (newTargetValue & 0x00FF0000) >> 16;
+                               // update instruction to match codeToDataDelta 
+                               uint32_t newInstruction = (instruction & 0x8F00FBF0) | imm4_ | (i_ << 10) | (imm3_ << 28) | (imm8_ << 16);
+                               A::P::E::set32(*p, newInstruction);
+                       }
+                       break;
+               case 0x20:
+               case 0x21:
+               case 0x22:
+               case 0x23:
+               case 0x24:
+               case 0x25:
+               case 0x26:
+               case 0x27:
+               case 0x28:
+               case 0x29:
+               case 0x2A:
+               case 0x2B:
+               case 0x2C:
+               case 0x2D:
+               case 0x2E:
+               case 0x2F:
+                       // used by arm movt (low nibble of kind is high 4-bits of paired movw)
+                       {
+                               p = (uint32_t*)mappedAddressForVMAddress(address);
+                               instruction = A::P::E::get32(*p);
+                               // extract 16-bit value from instruction
+                               uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+                               uint32_t imm12 = (instruction & 0x00000FFF);
+                               uint32_t imm16 = (imm4 << 12) | imm12;
+                               // combine with codeToDataDelta and kind nibble
+                               uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
+                               uint32_t newTargetValue = targetValue + codeToDataDelta;
+                               // construct new bits slices
+                               uint32_t imm4_  = (newTargetValue & 0xF0000000) >> 28;
+                               uint32_t imm12_ = (newTargetValue & 0x0FFF0000) >> 16;
+                               // update instruction to match codeToDataDelta 
+                               uint32_t newInstruction = (instruction & 0xFFF0F000) | (imm4_ << 16) | imm12_;
+                               A::P::E::set32(*p, newInstruction);
+                       }
+                       break;
+               case 3: // used only for ppc, an instruction that sets the hi16 of a register
                default:
                        throwf("invalid kind=%d in split seg info", kind);
        }
@@ -663,7 +739,13 @@ void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::v
        switch ( type ) {
                case REBASE_TYPE_POINTER:
                        valueP= P::getP(*mappedAddrP);
-                       P::setP(*mappedAddrP, valueP + this->getSlideForVMAddress(valueP));
+                       try {
+                               P::setP(*mappedAddrP, valueP + this->getSlideForVMAddress(valueP));
+                       }
+                       catch (const char* msg) {
+                               throwf("at offset=0x%08llX in seg=%s, pointer cannot be rebased because it does not point to __TEXT or __DATA. %s\n", 
+                                               segOffset, seg.name(), msg);
+                       }
                        break;
                
                case REBASE_TYPE_TEXT_ABSOLUTE32:
@@ -842,27 +924,6 @@ void Rebaser<x86_64>::doLocalRelocation(const macho_relocation_info<x86_64::P>*
        }
 }
 
-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)
 {
@@ -972,9 +1033,6 @@ public:
                                        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_I386:
                                                                fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
                                                                break;
@@ -995,10 +1053,7 @@ public:
                        }
                        else {
                                try {
-                                       if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
-                                               fRebasers.push_back(new Rebaser<ppc>(mh));
-                                       }
-                                       else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+                                       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)) {
index 43ab45a6dac98aadc0ced69e1a2880ce83eef9b9..19ee2d3f4bc08295cc6378ee1fbe73044838758c 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#define OBJC_IMAGE_SUPPORTS_GC (1<<1)
+#define OBJC_IMAGE_REQUIRES_GC (1<<2)
+
 template <typename A>
 struct objc_image_info {
     uint32_t version;
     uint32_t flags;
 
+    uint32_t getFlags()         INLINE { return A::P::E::get32(flags); }
+    
+    bool supportsGCFlagSet()    INLINE { return getFlags() & OBJC_IMAGE_SUPPORTS_GC; }
+    bool requiresGCFlagSet()    INLINE { return getFlags() & OBJC_IMAGE_REQUIRES_GC; }
+    
     void setFlag(uint32_t bits) INLINE { uint32_t old = A::P::E::get32(flags); A::P::E::set32(flags, old | bits); }
-    void setSelectorsPrebound() INLINE { setFlag(1<<3); }
+    void setOptimizedByDyld() INLINE { setFlag(1<<3); }
 };
 
 template <typename A>
@@ -221,14 +229,5 @@ public:
             uint64_t newValue = visitor.visit(oldValue);
             selrefs.set(s, newValue);
         }
-
-        // Mark image_info
-        const macho_section<P> *imageInfoSection = 
-            header->getSection("__OBJC", "__image_info");
-        if (imageInfoSection) {
-            objc_image_info<A> *info = (objc_image_info<A> *)
-                cache->mappedAddressForVMAddress(imageInfoSection->addr());
-            info->setSelectorsPrebound();
-        }
     }
 };
index 9dc9b90adcad59e5de6a99df4658d0047a581f5f..41419a88300d452c965b1d706a6986b9800e987c 100644 (file)
@@ -22,6 +22,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include "MachOLayout.hpp"
 #include <iterator>
 #include <deque>
 
@@ -76,7 +77,7 @@ struct entsize_iterator {
     }
     
     T& operator * () { return *current; }
-    const T& operator * () const { return *current; }
+    T& operator * () const { return *current; }
     T& operator -> () { return *current; }
     const T& operator -> () const { return *current; }
     
@@ -107,6 +108,44 @@ struct entsize_iterator {
         }
     }
 };
+
+template <typename A> 
+class objc_header_info_t {
+
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+
+    pint_t next;   // objc_header_info *
+    pint_t mhdr;   // mach_header or mach_header_64
+    pint_t info;   // objc_image_info *
+    pint_t fname;  // const char *
+    bool loaded; 
+    bool inSharedCache;
+    bool allClassesRealized;
+
+public:
+    objc_header_info_t(SharedCache<A>* cache, const macho_header<P>* mh) 
+        : next(0), 
+          mhdr(0), 
+          info(0), 
+          fname(0), 
+          loaded(0), 
+          allClassesRealized(0)
+    {
+        A::P::setP(mhdr, cache->VMAddressForMappedAddress(mh));
+        const macho_section<P>* sect = mh->getSection("__DATA", "__objc_imageinfo");
+        if (sect) A::P::setP(info, sect->addr());
+
+        // can't set fname because dyld sometimes edits it
+    }
+
+       void addPointers(std::vector<void*>& pointersToAdd) {
+        pointersToAdd.push_back(&mhdr);
+        if (info) pointersToAdd.push_back(&info);
+    }
+
+    uint64_t header_vmaddr() const { return mhdr; }
+};
   
 template <typename A> class objc_method_list_t;  // forward reference
 
@@ -203,15 +242,30 @@ public:
 
 template <typename A>
 class objc_ivar_t {
+    typedef typename A::P::uint_t pint_t;
     typename A::P::uint_t offset;  // A::P *
     typename A::P::uint_t name;    // const char *
     typename A::P::uint_t type;    // const char *
     uint32_t alignment; 
     uint32_t size;
+    
+public:
+    const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
+
+    bool hasOffset() const { return A::P::getP(offset) != 0; }
+    pint_t getOffset(SharedCache<A> *cache) const { return A::P::getP(*(pint_t * const)cache->mappedAddressForVMAddress(A::P::getP(offset))); }
+    void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::setP(*(pint_t *)cache->mappedAddressForVMAddress(A::P::getP(offset)), newOffset); }
+    
+    uint32_t getAlignment()
+    {
+        uint32_t a = A::P::E::get32(alignment);
+        return a == (uint32_t)-1 ? sizeof(typename A::P::uint_t) : 1<<a;
+    }
 };
 
 template <typename A>
 class objc_ivar_list_t {
+    typedef typename A::P::uint_t pint_t;
     uint32_t entsize;
     uint32_t count;
     objc_ivar_t<A> first;
@@ -228,7 +282,7 @@ public:
 
        uint32_t getEntsize() const { return A::P::E::get32(entsize); }
 
-    objc_ivar_t<A>& get(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
+    objc_ivar_t<A>& get(pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
 
     uint32_t byteSize() const { 
         return byteSizeForCount(getCount(), getEntsize()); 
@@ -440,10 +494,20 @@ class objc_class_data_t {
     typename A::P::uint_t baseProperties;
 
 public:
+    bool isMetaClass() { return A::P::E::get32(flags) & 1; }
+
+    uint32_t getInstanceStart() { return A::P::E::get32(instanceStart); }
+    void setInstanceStart(uint32_t newStart) { A::P::E::set32(instanceStart, newStart); }
+    
+    uint32_t getInstanceSize() { return A::P::E::get32(instanceSize.instanceSize); }
+    void setInstanceSize(uint32_t newSiz) { A::P::E::set32(instanceSize.instanceSize, newSiz); }
+
     objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
 
     objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
 
+    objc_ivar_list_t<A> *getIvarList(SharedCache<A>* cache) const { return (objc_ivar_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); }
+    
     objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
 
     const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
@@ -482,8 +546,12 @@ class objc_class_t {
     typename A::P::uint_t data;
 
 public:
+    bool isMetaClass(SharedCache<A>* cache) const { return getData(cache)->isMetaClass(); }
+
     objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
 
+    objc_class_t<A> *getSuperclass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); }
+    
     objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
 
     objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
@@ -570,6 +638,60 @@ public:
     void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
 };
 
+// Call visitor.visitIvar() on every ivar in a given class.
+template <typename A, typename V>
+class IvarWalker {
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+    V& ivarVisitor;
+public:
+    
+    IvarWalker(V& visitor) : ivarVisitor(visitor) { }
+    
+    void walk(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
+    {
+        objc_class_data_t<A> *data = cls->getData(cache);
+        objc_ivar_list_t<A> *ivars = data->getIvarList(cache);
+        if (ivars) {
+            for (pint_t i = 0; i < ivars->getCount(); i++) {
+                objc_ivar_t<A>& ivar = ivars->get(i);
+                //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
+                ivarVisitor.visitIvar(cache, header, cls, &ivar);
+            }
+        } else {
+            //fprintf(stderr, "no ivars\n");
+        }
+    }
+    
+    void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
+    {
+        walk(cache, header, cls);
+    }
+};
+
+// Call visitor.visitClass() on every class.
+template <typename A, typename V>
+class ClassWalker {
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+    V& classVisitor;
+public:
+    
+    ClassWalker(V& visitor) : classVisitor(visitor) { }
+    
+    void walk(SharedCache<A>* cache, const macho_header<P>* header)
+    {   
+        PointerSection<A, objc_class_t<A> *> 
+        classes(cache, header, "__DATA", "__objc_classlist");
+        
+        for (pint_t i = 0; i < classes.count(); i++) {
+            objc_class_t<A> *cls = classes.get(i);
+            //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
+            classVisitor.visitClass(cache, header, cls);
+        }
+    }
+};
+
 
 // Call visitor.visitMethodList(mlist) on every method list in a header.
 template <typename A, typename V>
@@ -584,7 +706,7 @@ public:
     
     MethodListWalker(V& visitor) : mVisitor(visitor) { }
 
-    void walk(SharedCache<A>* cache, const macho_header<P>* header)
+    void walk(SharedCache<A>* cache, const macho_header<P>* header, bool walkProtocols)
     {   
         // Method lists in classes
         PointerSection<A, objc_class_t<A> *> 
@@ -615,25 +737,27 @@ public:
             }
         }
 
-        // Method description lists from protocols
-        PointerSection<A, objc_protocol_t<A> *> 
-            protocols(cache, header, "__DATA", "__objc_protolist");
-        for (pint_t i = 0; i < protocols.count(); i++) {
-            objc_protocol_t<A> *proto = protocols.get(i);
-            objc_method_list_t<A> *mlist;
-            if ((mlist = proto->getInstanceMethods(cache))) {
-                mVisitor.visitMethodList(mlist);
-            }
-            if ((mlist = proto->getClassMethods(cache))) {
-                mVisitor.visitMethodList(mlist);
-            }
-            if ((mlist = proto->getOptionalInstanceMethods(cache))) {
-                mVisitor.visitMethodList(mlist);
-            }
-            if ((mlist = proto->getOptionalClassMethods(cache))) {
-                mVisitor.visitMethodList(mlist);
-            }
-        }
+               // Method description lists from protocols
+               if ( walkProtocols ) {
+                       PointerSection<A, objc_protocol_t<A> *> 
+                               protocols(cache, header, "__DATA", "__objc_protolist");
+                       for (pint_t i = 0; i < protocols.count(); i++) {
+                               objc_protocol_t<A> *proto = protocols.get(i);
+                               objc_method_list_t<A> *mlist;
+                               if ((mlist = proto->getInstanceMethods(cache))) {
+                                       mVisitor.visitMethodList(mlist);
+                               }
+                               if ((mlist = proto->getClassMethods(cache))) {
+                                       mVisitor.visitMethodList(mlist);
+                               }
+                               if ((mlist = proto->getOptionalInstanceMethods(cache))) {
+                                       mVisitor.visitMethodList(mlist);
+                               }
+                               if ((mlist = proto->getOptionalClassMethods(cache))) {
+                                       mVisitor.visitMethodList(mlist);
+                               }
+                       }
+               }
     }
 };
 
@@ -667,7 +791,7 @@ public:
     {
         // method lists of all kinds
         MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
-        mw.walk(cache, header);
+        mw.walk(cache, header, true);
         
         // @selector references
         PointerSection<A, const char *> 
@@ -687,14 +811,96 @@ public:
             pint_t newValue = mVisitor.visit(oldValue);
             msg.setName(newValue);
         }
+    }
+};
 
-        // Mark image_info
-        const macho_section<P> *imageInfoSection = 
-            header->getSection("__DATA", "__objc_imageinfo");
+
+// Update selector references. The visitor performs recording and uniquing.
+template <typename A>
+class IvarOffsetOptimizer {
+    typedef typename A::P P;
+
+    uint32_t slide;
+    uint32_t maxAlignment;
+
+    uint32_t fOptimized;
+
+public:
+    
+    IvarOffsetOptimizer() : fOptimized(0) { }
+
+    size_t optimized() const { return fOptimized; }
+    
+    // dual purpose ivar visitor function
+    // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
+    void visitIvar(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls, objc_ivar_t<A> *ivar)
+    {
+        if (slide == 0) {
+            uint32_t alignment = ivar->getAlignment();
+            if (alignment > maxAlignment) maxAlignment = alignment;
+        } else {
+            // skip anonymous bitfields
+            if (ivar->hasOffset()) {
+                uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
+                ivar->setOffset(cache, oldOffset + slide);
+                fOptimized++;
+                //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
+            } else {
+                //fprintf(stderr, "NULL offset\n");
+            }
+        }
+    }
+    
+    // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
+    // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
+    void visitClass(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls)
+    {
+        objc_class_t<A> *super = cls->getSuperclass(cache);
+        if (super) {
+            // Recursively visit superclasses to ensure we have the correct superclass start
+            // Note that we don't need the macho_header, so just pass NULL.
+            visitClass(cache, NULL, super);
+
+            objc_class_data_t<A> *data = cls->getData(cache);
+            objc_class_data_t<A> *super_data = super->getData(cache);
+            int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
+            if (diff > 0) {
+                IvarWalker<A, IvarOffsetOptimizer<A> > ivarVisitor(*this);
+                maxAlignment = 0;
+                slide = 0;
+                
+                // This walk computes maxAlignment
+                ivarVisitor.walk(cache, NULL, cls);
+
+                // Compute a slide value that preserves that alignment
+                uint32_t alignMask = maxAlignment - 1;
+                if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
+
+                // Slide all of this class's ivars en masse
+                slide = diff;
+                if (slide != 0) {
+                    //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
+                    ivarVisitor.walk(cache, NULL, cls);
+                    data->setInstanceStart(data->getInstanceStart() + slide);
+                    data->setInstanceSize(data->getInstanceSize() + slide);
+                }
+            }
+        }
+    }
+    
+    // Enumerates objc classes in the module and performs any ivar slides
+    void optimize(SharedCache<A>* cache, const macho_header<P>* header)
+    {
+        // The slide code cannot fix up GC layout strings so skip modules that support ore require GC
+        const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
         if (imageInfoSection) {
-            objc_image_info<A> *info = (objc_image_info<A> *)
-                cache->mappedAddressForVMAddress(imageInfoSection->addr());
-            info->setSelectorsPrebound();
+            objc_image_info<A> *info = (objc_image_info<A> *)cache->mappedAddressForVMAddress(imageInfoSection->addr());
+            if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
+                ClassWalker<A, IvarOffsetOptimizer<A> > classVisitor(*this);
+                classVisitor.walk(cache, header);
+            } else {
+                //fprintf(stderr, "GC support present - skipped module\n");
+            }
         }
     }
 };
@@ -707,548 +913,76 @@ class MethodListSorter {
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
+    uint32_t fOptimized;
+
     friend class MethodListWalker<A, MethodListSorter<A> >;
     void visitMethodList(objc_method_list_t<A> *mlist)
     {
         typename objc_method_t<A>::SortBySELAddress sorter;
         std::stable_sort(mlist->begin(), mlist->end(), sorter);
         mlist->setFixedUp();
+        fOptimized++;
     }
 
 public:
+    MethodListSorter() : fOptimized(0) { }
+
+    size_t optimized() const { return fOptimized; }
 
     void optimize(SharedCache<A>* cache, macho_header<P>* header)
     {
         MethodListWalker<A, MethodListSorter<A> > mw(*this);
-        mw.walk(cache, header);
+        mw.walk(cache, header, false /* don't sort protocol method lists*/);
     }
 };
 
 
-// Attach categories to classes in the same framework. 
-// Merge method and protocol and property lists.
 template <typename A>
-class CategoryAttacher {
+class HeaderInfoOptimizer {
 
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
-    uint8_t *mBytes;
-    ssize_t mBytesFree;
-    ssize_t mBytesUsed;
-
-    size_t mCategoriesAttached;
+    objc_header_info_t<A>* fHinfos;
+    size_t fCount;
 
-    bool segmentContainsPointer(SharedCache<A>* cache, 
-                                const macho_segment_command<P>* seg, void *ptr)
-    {
-        if (!seg) return false;
-        void *start = (void*)
-            cache->mappedAddressForVMAddress(seg->vmaddr());
-        void *end   = (uint8_t *)start + seg->filesize();
-        return (ptr >= start  &&  ptr < end);
-    }
+public:
+    HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
 
-    bool headerContainsPointer(SharedCache<A>* cache, 
-                               macho_header<P>* header, void *ptr)
+    const char *init(size_t count, uint8_t*& buf, size_t& bufSize)
     {
-        return 
-            segmentContainsPointer(cache, header->getSegment("__DATA"), ptr) ||
-            segmentContainsPointer(cache, header->getSegment("__TEXT"), ptr) ||
-            segmentContainsPointer(cache, header->getSegment("__OBJC"), ptr);
-    }
-
-    struct pointer_hash {
-        size_t operator () (void* ptr) const { 
-            return __gnu_cxx::hash<long>()((long)ptr); 
-        }
-    };
-
-    typedef std::deque<objc_category_t<A>*> CategoryList;
-    typedef std::vector<uint64_t> CategoryRefs;
-
-    struct ClassChanges {
-        CategoryList categories;
-        CategoryRefs catrefs;
-        
-        objc_method_list_t<A>* instanceMethods;
-        objc_method_list_t<A>* classMethods;
-        objc_protocol_list_t<A>* protocols;
-        objc_property_list_t<A>* instanceProperties;
-
-        ClassChanges() 
-            : instanceMethods(NULL), classMethods(NULL), 
-              protocols(NULL), instanceProperties(NULL)
-        { }
-
-        ~ClassChanges() { 
-            if (instanceMethods) delete instanceMethods;
-            if (classMethods) delete classMethods;
-            if (protocols) delete protocols;
-            if (instanceProperties) delete instanceProperties;
-        }
-    };
-
-    typedef __gnu_cxx::hash_map<objc_class_t<A>*, ClassChanges, pointer_hash> ClassMap;
-
-    class RangeArray {
-        typedef std::pair<uint8_t*,uint32_t> Range;
-        std::deque<Range> ranges;
+        if (count == 0) return NULL;
 
-        class SizeFits {
-        private:
-            uint32_t mSize;
-        public:
-            SizeFits(uint32_t size) : mSize(size) { } 
-            bool operator() (const Range& r) { 
-                return r.second >= mSize;
-            }
-        };
-
-        struct AddressComp {
-            bool operator() (const Range& lhs, const Range& rhs) {
-                return (lhs.first < rhs.first);
-            }
-        };
-    public:
-        RangeArray() { }
-        void add(void* p, uint32_t size) {
-            add(Range((uint8_t *)p, size));
+        if (bufSize < 2*sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>)) {
+            return "libobjc's read/write section is too small (metadata not optimized)";
         }
-        void add(const Range& r) {
-            // find insertion point
-            std::deque<Range>::iterator iter;
-            iter = upper_bound(ranges.begin(), ranges.end(), r, AddressComp());
-            // coalesce
-            // fixme doesn't fully coalesce if new range exactly fills a gap
-            if (iter != ranges.begin()) {
-                std::deque<Range>::iterator prev = iter - 1;
-                if ((*prev).first + (*prev).second == r.first) {
-                    (*prev).second += r.second;
-                    return;
-                }
-            }
-            if (iter != ranges.end()  &&  iter+1 != ranges.end()) {
-                std::deque<Range>::iterator next = iter + 1;
-                if (r.first + r.second == (*next).first) {
-                    (*next).second += r.second;
-                    (*next).first = r.first;
-                    return;
-                }
-            }
-            ranges.insert(iter, r);
-        }
-
-        uint8_t* remove(uint32_t size) {
-            // first-fit search
-            // this saves 50-75% of space overhead; 
-            // a better algorithm might do better
-
-            std::deque<Range>::iterator iter;
-            iter = find_if(ranges.begin(), ranges.end(), SizeFits(size));
-            if (iter == ranges.end()) {
-                return NULL;
-            }
 
-            Range& found = *iter;
-            uint8_t *result = found.first;
-            if (found.second > size) {
-                // keep leftovers
-                found.first += size;
-                found.second -= size;
-            } else {
-                ranges.erase(iter);
-            }
+        uint32_t *buf32 = (uint32_t *)buf;
+        A::P::E::set32(buf32[0], count);
+        A::P::E::set32(buf32[1], sizeof(objc_header_info_t<A>));
+        fHinfos = (objc_header_info_t<A>*)(buf32+2);
 
-            return result;
-        }
-    };
+        size_t total = sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>);
+        buf += total;
+        bufSize -= total;
 
-    void copyMethods(typename objc_method_list_t<A>::method_iterator& dst, 
-                     const objc_method_list_t<A>* srcList)
-    {
-        objc_method_list_t<A>::method_iterator::
-            overwrite(dst, srcList);
+        return NULL;
     }
 
-    void copyProperties(typename objc_property_list_t<A>::property_iterator& dst, 
-                        const objc_property_list_t<A>* srcList)
-    {
-        objc_property_list_t<A>::property_iterator::
-            overwrite(dst, srcList);
+    void update(SharedCache<A>* cache, const macho_header<P>* mh, std::vector<void*>& pointersInData)
+    { 
+        objc_header_info_t<A>* hi = new(&fHinfos[fCount++]) objc_header_info_t<A>(cache, mh);
+        hi->addPointers(pointersInData);
     }
 
-    void copyProtocols(objc_protocol_list_t<A>* dst, pint_t& dstIndex,
-                       const objc_protocol_list_t<A>* src)
+    objc_header_info_t<A>* hinfoForHeader(SharedCache<A>* cache, const macho_header<P>* mh)
     {
-        dst->overwrite(dstIndex, src);
-    }
-
-       class InSet
-       {
-       public:
-               InSet(std::set<void*>& deadPointers) : _deadPointers(deadPointers) {}
-
-               bool operator()(void* ptr) const {
-                       return ( _deadPointers.count(ptr) != 0 );
-               }
-
-       private:
-               std::set<void*>& _deadPointers;
-       };
-
-public:
-
-    CategoryAttacher(uint8_t *bytes, ssize_t bytesFree) 
-        : mBytes(bytes), mBytesFree(bytesFree)
-        , mBytesUsed(0), mCategoriesAttached(0) 
-    { }
-
-    size_t count() const { return mCategoriesAttached; }
-
-    const char *optimize(SharedCache<A>* cache, macho_header<P>* header, std::vector<void*>& pointersInData)
-    {
-        // Build class=>cateories mapping.
-        // Disregard target classes that aren't in this binary.
-
-        ClassMap map;
-
-               PointerSection<A, objc_category_t<A> *> 
-            nlcatsect(cache, header, "__DATA", "__objc_nlcatlist");
-        PointerSection<A, objc_category_t<A> *> 
-            catsect(cache, header, "__DATA", "__objc_catlist");
-        for (pint_t i = 0; i < catsect.count(); i++) {
-            objc_category_t<A> *cat = catsect.get(i);
-            objc_class_t<A> *cls = cat->getClass(cache);
-            if (!cls) continue;
-            if (!headerContainsPointer(cache, header, cls)) continue;
-                       if ( nlcatsect.count() !=0 ) {
-                               // don't optimize categories also in __objc_nlcatlist
-                               bool alsoInNlcatlist = false;
-                               for (pint_t nli = 0; nli < nlcatsect.count(); nli++) {
-                                       if ( nlcatsect.get(nli) == cat ) {
-                                               //fprintf(stderr, "skipping cat in __objc_nlcatlist for mh=%p\n", header);
-                                               alsoInNlcatlist = true;
-                                               break;
-                                       }
-                               }
-                               if ( alsoInNlcatlist ) 
-                                       continue;
-                       }
-
-            // The LAST category found is the FIRST to be processed later.
-            map[cls].categories.push_front(cat);
-
-            // We don't care about the category reference order.
-            map[cls].catrefs.push_back(i);
-        }
-
-        if (map.size() == 0) {
-            // No attachable categories.
-            return NULL;
-        }
-
-        // Process each class.
-        // Each class is all-or-nothing: either all of its categories 
-        // are attached successfully, or none of them are. This preserves 
-        // cache validity if we run out of space for more reallocations.
-
-        // unusedMemory stores memory ranges evacuated by now-unused metadata.
-        // It is available for re-use by other newly-added metadata.
-        // fixme could packing algorithm be improved?
-        RangeArray unusedMemory;
-
-        ssize_t reserve = 0;
-
-        // First: build new aggregated lists on the heap.
-        // Require enough space in mBytes for all of it.
-
-               std::set<void*> pointersToRemove;
-        for (typename ClassMap::iterator i = map.begin(); 
-             i != map.end(); 
-             ++i) 
-        {
-            objc_class_t<A>* cls = i->first;
-            objc_class_t<A>* meta = cls->getIsa(cache);
-            ClassChanges& changes = i->second;
-            CategoryList& cats = changes.categories;
-
-            // Count memory needed for all categories on this class.
-
-            uint32_t methodEntsize = 0;
-            uint32_t propertyEntsize = 0;
-            objc_method_list_t<A>* mlist;
-            objc_property_list_t<A>* proplist;
-            objc_protocol_list_t<A>* protolist;
-            uint32_t instanceMethodsCount = 0;
-            uint32_t classMethodsCount = 0;
-            uint32_t instancePropertyCount = 0;
-            pint_t protocolCount = 0;
-            bool addedInstanceMethods = false;
-            bool addedClassMethods = false;
-            bool addedInstanceProperties = false;
-            bool addedProtocols = false;
-
-            mlist = cls->getMethodList(cache);
-            if (mlist) {
-                instanceMethodsCount = mlist->getCount();
-                methodEntsize = 
-                    std::max(methodEntsize, mlist->getEntsize());
-            }
-
-            mlist = meta->getMethodList(cache);
-            if (mlist) {
-                classMethodsCount = mlist->getCount();
-                methodEntsize = 
-                    std::max(methodEntsize, mlist->getEntsize());
-            }
-
-            proplist = cls->getPropertyList(cache);
-            if (proplist) {
-                instancePropertyCount = proplist->getCount();
-                propertyEntsize = 
-                    std::max(propertyEntsize, proplist->getEntsize());
-            }
-
-            protolist = cls->getProtocolList(cache);
-            if (protolist) {
-                protocolCount = protolist->getCount();
-            }
-
-            typename CategoryList::iterator j;
-            for (j = cats.begin(); j != cats.end(); ++j) {
-                objc_category_t<A>* cat = *j;
-
-                mlist = cat->getInstanceMethods(cache);
-                if (mlist  &&  mlist->getCount() > 0) {
-                    addedInstanceMethods = true;
-                    instanceMethodsCount += mlist->getCount();
-                    methodEntsize = 
-                        std::max(methodEntsize, mlist->getEntsize());
-                }
-
-                mlist = cat->getClassMethods(cache);
-                if (mlist  &&  mlist->getCount() > 0) {
-                    addedClassMethods = true;
-                    classMethodsCount += mlist->getCount();
-                    methodEntsize = 
-                        std::max(methodEntsize, mlist->getEntsize());
-                }
-
-                proplist = cat->getInstanceProperties(cache);
-                if (proplist  &&  proplist->getCount() > 0) {
-                    addedInstanceProperties = true;
-                    instancePropertyCount += proplist->getCount();
-                    propertyEntsize = 
-                        std::max(propertyEntsize, proplist->getEntsize());
-                }
-
-                protolist = cat->getProtocols(cache);
-                if (protolist  &&  protolist->getCount() > 0) {
-                    addedProtocols = true;
-                    protocolCount += protolist->getCount();
-                }
-            }
-
-            // Allocate memory for aggregated lists. 
-            // Reserve the same amount of space from mBytes.
-
-            if (addedInstanceMethods) {
-                changes.instanceMethods = objc_method_list_t<A>::newMethodList(instanceMethodsCount, methodEntsize);
-                reserve = P::round_up(reserve + changes.instanceMethods->byteSize());
-            }
-            if (addedClassMethods) {
-                changes.classMethods = objc_method_list_t<A>::newMethodList(classMethodsCount, methodEntsize);
-                reserve = P::round_up(reserve + changes.classMethods->byteSize());
-            }
-            if (addedInstanceProperties) {
-                changes.instanceProperties = objc_property_list_t<A>::newPropertyList(instancePropertyCount, propertyEntsize);
-                reserve = P::round_up(reserve + changes.instanceProperties->byteSize());
-            }
-            if (addedProtocols) {
-                changes.protocols = objc_protocol_list_t<A>::newProtocolList(protocolCount);
-                reserve = P::round_up(reserve + changes.protocols->byteSize());
-            }
-
-                       // Merge. The LAST category's contents ends up FIRST in each list.
-                       // The aggregated lists are not sorted; a future pass does that.
-
-            typename objc_method_list_t<A>::method_iterator newInstanceMethods;
-            typename objc_method_list_t<A>::method_iterator newClassMethods;
-            typename objc_property_list_t<A>::property_iterator newInstanceProperties;
-            pint_t newProtocolIndex;
-
-            if (addedInstanceMethods) {
-                newInstanceMethods = changes.instanceMethods->begin();
-            }
-            if (addedClassMethods) {
-                newClassMethods = changes.classMethods->begin();
-            }
-            if (addedInstanceProperties) {
-                newInstanceProperties = changes.instanceProperties->begin();
-            }
-            if (addedProtocols) {
-                newProtocolIndex = 0;
-            }
-            
-            for (j = cats.begin(); j != cats.end(); ++j) {
-                objc_category_t<A>* cat = *j;
-
-                mlist = cat->getInstanceMethods(cache);
-                if (mlist) {
-                    copyMethods(newInstanceMethods, mlist);
-                                       mlist->getPointers(pointersToRemove);
-                    unusedMemory.add(mlist, mlist->byteSize());
-                }
-
-                mlist = cat->getClassMethods(cache);
-                if (mlist) {
-                    copyMethods(newClassMethods, mlist);
-                                       mlist->getPointers(pointersToRemove);
-                                       unusedMemory.add(mlist, mlist->byteSize());
-                }
-
-                proplist = cat->getInstanceProperties(cache);
-                if (proplist) {
-                    copyProperties(newInstanceProperties, proplist);
-                                       proplist->getPointers(pointersToRemove);
-                                       unusedMemory.add(proplist, proplist->byteSize());
-                }
-
-                protolist = cat->getProtocols(cache);
-                if (protolist) {
-                    copyProtocols(changes.protocols, newProtocolIndex, protolist);
-                                       protolist->getPointers(pointersToRemove);
-                                       unusedMemory.add(protolist, protolist->byteSize());
-                }
-
-                               cat->getPointers(pointersToRemove);
-                               unusedMemory.add(cat, sizeof(*cat));                
-            }
-
-            if (addedInstanceMethods && (mlist = cls->getMethodList(cache))) {
-                copyMethods(newInstanceMethods, mlist);
-                               mlist->getPointers(pointersToRemove);
-                               unusedMemory.add(mlist, mlist->byteSize());
-            }
-            if (addedClassMethods && (mlist = meta->getMethodList(cache))) {
-                copyMethods(newClassMethods, mlist);
-                               mlist->getPointers(pointersToRemove);
-                unusedMemory.add(mlist, mlist->byteSize());
-            }
-            if (addedInstanceProperties && (proplist = cls->getPropertyList(cache))) {
-                copyProperties(newInstanceProperties, proplist);
-                               proplist->getPointers(pointersToRemove);
-                               unusedMemory.add(proplist, proplist->byteSize());
-            }
-            if (addedProtocols && (protolist = cls->getProtocolList(cache))) {
-                copyProtocols(changes.protocols, newProtocolIndex, protolist);
-                               protolist->getPointers(pointersToRemove);
-                unusedMemory.add(protolist, protolist->byteSize());
-            }
+        // fixme could be binary search
+        pint_t mh_vmaddr = cache->VMAddressForMappedAddress(mh);
+        for (size_t i = 0; i < fCount; i++) {
+            objc_header_info_t<A>* hi = &fHinfos[i];
+            if (hi->header_vmaddr() == mh_vmaddr) return hi;
         }
-
-               if (reserve > mBytesFree) {
-                       return "insufficient space for category data (metadata not optimized)";
-               }
-
-               // update cache slide info and remove areas now longer containing pointers
-               //fprintf(stderr, "found %lu pointers in objc structures being moved\n", pointersToRemove.size());
-               pointersInData.erase(std::remove_if(pointersInData.begin(), pointersInData.end(), InSet(pointersToRemove)), pointersInData.end());
-               
-
-               // All lists are now built.
-        // mBytes is big enough to hold everything if necessary.
-        // Everything in unusedMemory is now available for re-use.
-        // The original metadata is still untouched.
-
-        // Second: write lists into mBytes and unusedMemory, 
-        // then disconnect categories.
-
-        for (typename ClassMap::iterator i = map.begin(); 
-             i != map.end(); 
-             ++i) 
-        {
-            objc_class_t<A>* cls = i->first;
-            objc_class_t<A>* meta = cls->getIsa(cache);
-            ClassChanges& changes = i->second;
-
-            // Write lists.
-            
-            if (changes.instanceMethods) {
-                uint8_t *bytes;
-                uint32_t size = changes.instanceMethods->byteSize();
-                if (! (bytes = unusedMemory.remove(size))) {
-                    bytes = mBytes + mBytesUsed;
-                    mBytesFree -= size;
-                    mBytesUsed += size;
-                }
-                memcpy(bytes, changes.instanceMethods, size);
-                               objc_method_list_t<A>::addPointers(bytes, pointersInData);
-                               cls->setMethodList(cache, (objc_method_list_t<A> *)bytes);
-                               cls->addMethodListPointer(cache, pointersInData);
-            }
-            
-            if (changes.classMethods) {
-                uint8_t *bytes;
-                uint32_t size = changes.classMethods->byteSize();
-                if (! (bytes = unusedMemory.remove(size))) {
-                    bytes = mBytes + mBytesUsed;
-                    mBytesFree -= size;
-                    mBytesUsed += size;
-                }
-                memcpy(bytes, changes.classMethods, size);
-                               objc_method_list_t<A>::addPointers(bytes, pointersInData);
-                               meta->setMethodList(cache, (objc_method_list_t<A> *)bytes);
-                               meta->addMethodListPointer(cache, pointersInData);
-            }
-            
-            if (changes.instanceProperties) {
-                uint8_t *bytes;
-                uint32_t size = changes.instanceProperties->byteSize();
-                if (! (bytes = unusedMemory.remove(size))) {
-                    bytes = mBytes + mBytesUsed;
-                    mBytesFree -= size;
-                    mBytesUsed += size;
-                }
-                memcpy(bytes, changes.instanceProperties, size);
-                               objc_property_list_t<A>::addPointers(bytes, pointersInData);
-                cls->setPropertyList(cache, (objc_property_list_t<A> *)bytes);
-                               cls->addPropertyListPointer(cache, pointersInData);
-          }
-
-            if (changes.protocols) {
-                uint8_t *bytes;
-                uint32_t size = changes.protocols->byteSize();
-                if (! (bytes = unusedMemory.remove(size))) {
-                    bytes = mBytes + mBytesUsed;
-                    mBytesFree -= size;
-                    mBytesUsed += size;
-                }
-                memcpy(bytes, changes.protocols, size);
-                cls->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
-                               objc_protocol_list_t<A>::addPointers(bytes, pointersInData);
-                               cls->addProtocolListPointer(cache, pointersInData);
-                               meta->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
-                               meta->addProtocolListPointer(cache, pointersInData);
-          }
-
-            // Disavow all knowledge of the categories.
-
-            for (typename CategoryRefs::iterator j = changes.catrefs.begin();
-                 j != changes.catrefs.end();
-                 ++j)
-            {
-                catsect.set(*j, 0);
-            }
-
-            mCategoriesAttached += changes.categories.size();
-        }
-
-        catsect.removeNulls();
-
         return NULL;
     }
-
-    ssize_t bytesUsed() { return mBytesUsed; }
 };
index b86b3665b1115944bdc9466a17201cd3e65617c4..c94cbe0e645c4e4adef03d605763507b58075c51 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -85,6 +85,8 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
        macho_segment_command<P>* linkEditSegCmd = NULL;
        macho_symtab_command<P>* symtab = NULL;
        macho_dysymtab_command<P>*      dynamicSymTab = NULL;
+       macho_linkedit_data_command<P>* functionStarts = NULL;
+       macho_linkedit_data_command<P>* dataInCode = NULL;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                        // update segment/section file offsets
@@ -121,6 +123,12 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
                else if ( cmd->cmd() == LC_DYSYMTAB ) {
                        dynamicSymTab = (macho_dysymtab_command<P>*)cmd;
                }
+               else if ( cmd->cmd() == LC_FUNCTION_STARTS ) {
+                       functionStarts = (macho_linkedit_data_command<P>*)cmd;
+               }
+               else if ( cmd->cmd() == LC_DATA_IN_CODE ) {
+                       dataInCode = (macho_linkedit_data_command<P>*)cmd;
+               }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
        
@@ -137,8 +145,23 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
                fprintf(stderr, "LC_DYSYMTAB not found\n");
                return -1;
        }
+
+       const uint32_t newFunctionStartsOffset = linkEditSegCmd->fileoff();
+       uint32_t functionStartsSize = 0;
+       if ( functionStarts != NULL ) {
+               // copy function starts from original cache file to new mapped dylib file
+               functionStartsSize = functionStarts->datasize();
+               memcpy((char*)mh + newFunctionStartsOffset, (char*)mapped_cache + functionStarts->dataoff(), functionStartsSize);
+       }
+       const uint32_t newDataInCodeOffset = (newFunctionStartsOffset + functionStartsSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
+       uint32_t dataInCodeSize = 0;
+       if ( dataInCode != NULL ) {
+               // copy data-in-code info from original cache file to new mapped dylib file
+               dataInCodeSize = dataInCode->datasize();
+               memcpy((char*)mh + newDataInCodeOffset, (char*)mapped_cache + dataInCode->dataoff(), dataInCodeSize);
+       }
        // copy symbol entries and strings from original cache file to new mapped dylib file
-       const uint32_t newSymTabOffset = linkEditSegCmd->fileoff();
+       const uint32_t newSymTabOffset = (newDataInCodeOffset + dataInCodeSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
        const uint32_t newIndSymTabOffset = newSymTabOffset + symtab->nsyms()*sizeof(macho_nlist<P>);
        const uint32_t newStringPoolOffset = newIndSymTabOffset + dynamicSymTab->nindirectsyms()*sizeof(uint32_t);
        macho_nlist<P>* const newSymTabStart = (macho_nlist<P>*)(((uint8_t*)mh) + newSymTabOffset);
@@ -165,6 +188,14 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
        memcpy(newIndSymTab, mergedIndSymTab, dynamicSymTab->nindirectsyms()*sizeof(uint32_t));
        
        // update load commands
+       if ( functionStarts != NULL ) {
+               functionStarts->set_dataoff(newFunctionStartsOffset);
+               functionStarts->set_datasize(functionStartsSize);
+       }
+       if ( dataInCode != NULL ) {
+               dataInCode->set_dataoff(newDataInCodeOffset);
+               dataInCode->set_datasize(dataInCodeSize);
+       }
        symtab->set_symoff(newSymTabOffset);
        symtab->set_stroff(newStringPoolOffset);
        symtab->set_strsize(poolOffset);
@@ -290,7 +321,7 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
 } 
 
 
-extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path, const char* extraction_root_path,
+int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path, const char* extraction_root_path,
                                                                                                        void (^progress)(unsigned current, unsigned total))
 {
        struct stat statbuf;
@@ -319,14 +350,14 @@ extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_fi
                dylib_create_func = dylib_maker<x86>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1  x86_64") == 0 ) 
                dylib_create_func = dylib_maker<x86_64>;
-       else if ( strcmp((char*)mapped_cache, "dyld_v1     ppc") == 0 ) 
-               dylib_create_func = dylib_maker<ppc>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1   armv5") == 0 ) 
                dylib_create_func = dylib_maker<arm>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1   armv6") == 0 ) 
                dylib_create_func = dylib_maker<arm>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1   armv7") == 0 ) 
                dylib_create_func = dylib_maker<arm>;
+       else if ( strncmp((char*)mapped_cache, "dyld_v1  armv7", 14) == 0 ) 
+               dylib_create_func = dylib_maker<arm>;
        else {
                fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
         munmap(mapped_cache, statbuf.st_size);
@@ -343,7 +374,7 @@ extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_fi
 
        // for each dylib instantiate a dylib file
     dispatch_group_t        group               = dispatch_group_create();
-    dispatch_semaphore_t    sema                = dispatch_semaphore_create(4);
+    dispatch_semaphore_t    sema                = dispatch_semaphore_create(2);
     dispatch_queue_t        process_queue       = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
     dispatch_queue_t        writer_queue        = dispatch_queue_create("dyld writer queue", 0);
     
@@ -351,8 +382,8 @@ extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_fi
        __block unsigned        count               = 0;
     
        for ( NameToSegments::iterator it = map.begin(); it != map.end(); ++it) {
+        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
         dispatch_group_async(group, process_queue, ^{
-            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
             
             char    dylib_path[PATH_MAX];
             strcpy(dylib_path, extraction_root_path);
@@ -426,18 +457,35 @@ int dyld_shared_cache_extract_dylibs(const char* shared_cache_file_path, const c
 
 
 #if 0 
+
+typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
+                                                                                                       void (^progress)(unsigned current, unsigned total));
+
 int main(int argc, const char* argv[])
 {
        if ( argc != 3 ) {
                fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
                return 1;
        }
-               
-       int result = dyld_shared_cache_extract_dylibs_progress(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
+       
+       void* handle = dlopen("/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
+       if ( handle == NULL ) {
+               fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
+               return 1;
+       }
+       
+       extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
+       if ( proc == NULL ) {
+               fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
+               return 1;
+       }
+       
+       int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
        fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
        return 0;
 }
 #endif
 
-
 
index 9b5cac4f962f40a9a0d55a25e8db002949f9a2b9..50ff8c9ad5a521b9accecc155ace7a1a0eb41b41 100644 (file)
@@ -125,14 +125,14 @@ int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file,
                        return dyld::walkImages<x86>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1  x86_64") == 0 ) 
                        return dyld::walkImages<x86_64>(cache, callback);
-       else if ( strcmp((char*)cache, "dyld_v1     ppc") == 0 ) 
-                       return dyld::walkImages<ppc>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1   armv5") == 0 ) 
                        return dyld::walkImages<arm>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1   armv6") == 0 ) 
                        return dyld::walkImages<arm>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1   armv7") == 0 ) 
                        return dyld::walkImages<arm>(cache, callback);
+       else if ( strncmp((char*)cache, "dyld_v1  armv7", 14) == 0 ) 
+                       return dyld::walkImages<arm>(cache, callback);
        else
                return -1;
 }
diff --git a/launch-cache/dsc_slider.cpp b/launch-cache/dsc_slider.cpp
deleted file mode 100644 (file)
index d11f46a..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <Availability.h>
-
-#define NO_ULEB 1
-#include "dyld_cache_format.h"
-#include "Architectures.hpp"
-#include "MachOFileAbstraction.hpp"
-#include "CacheFileAbstraction.hpp"
-
-#include "dsc_slider.h"
-
-int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) )
-{
-       int fd = open(path, O_RDONLY, 0);
-       if ( fd == -1 ) {
-               (*logProc)("open(%s) failed, errno=%d\n", path, errno);
-               return -1;
-       }
-       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
-
-       uint8_t buffer[4096];
-       if ( read(fd, buffer, 4096) != 4096 ) {
-               (*logProc)("read(%s) failed, errno=%d\n", path, errno);
-               close(fd);
-               return -1;
-       }
-       bool has64BitPointers = false;
-       bool isBigEndian = false;
-       uint64_t startReadOnlySharedRegion = 0;
-       uint64_t endReadOnlySharedRegion = 0;
-       uint64_t startReadWriteSharedRegion = 0;
-       uint64_t endReadWriteSharedRegion = 0;
-       if ( strcmp((char*)buffer, "dyld_v1    i386") == 0 ) {
-               has64BitPointers = false;
-               isBigEndian = false;
-       }
-       else if ( strcmp((char*)buffer, "dyld_v1  x86_64") == 0 ) {
-               has64BitPointers = true;
-               isBigEndian = false;
-               startReadOnlySharedRegion  = 0x7FFF80000000LL;
-               endReadOnlySharedRegion    = 0x7FFFC0000000LL;
-               startReadWriteSharedRegion = 0x7FFF70000000LL;
-               endReadWriteSharedRegion   = 0x7FFF80000000LL;
-       }
-       else if ( strcmp((char*)buffer, "dyld_v1     ppc") == 0 ) {
-               has64BitPointers = false;
-               isBigEndian = true;
-       }
-       else if ( strcmp((char*)buffer, "dyld_v1   armv5") == 0 ) {
-               has64BitPointers = false;
-               isBigEndian = false;
-               startReadOnlySharedRegion  = 0x30000000LL;
-               endReadOnlySharedRegion    = 0x3E000000LL;
-               startReadWriteSharedRegion = 0x3E000000LL;
-               endReadWriteSharedRegion   = 0x40000000LL;
-       }
-       else if ( strcmp((char*)buffer, "dyld_v1   armv6") == 0 ) {
-               has64BitPointers = false;
-               isBigEndian = false;
-               startReadOnlySharedRegion  = 0x30000000LL;
-               endReadOnlySharedRegion    = 0x3E000000LL;
-               startReadWriteSharedRegion = 0x3E000000LL;
-               endReadWriteSharedRegion   = 0x40000000LL;
-       }
-       else if ( strcmp((char*)buffer, "dyld_v1   armv7") == 0 ) {
-               has64BitPointers = false;
-               isBigEndian = false;
-               startReadOnlySharedRegion  = 0x30000000LL;
-               endReadOnlySharedRegion    = 0x3E000000LL;
-               startReadWriteSharedRegion = 0x3E000000LL;
-               endReadWriteSharedRegion   = 0x40000000LL;
-       }
-       else {
-               (*logProc)("file %s is not a known dyld shared cache file\n", path);
-               close(fd);
-               return -1;
-       }
-#if __BIG_ENDIAN__ 
-       bool swap = !isBigEndian;
-#else
-       bool swap = isBigEndian;
-#endif
-       
-       const dyld_cache_header* header = (dyld_cache_header*)buffer;
-       uint32_t mappingOffset = swap ? OSSwapInt32(header->mappingOffset) : header->mappingOffset;
-       if ( mappingOffset < 0x48 ) {
-               (*logProc)("dyld shared cache file %s is old format\n", path);
-               close(fd);
-               return -1;
-       }
-
-       uint32_t mappingCount = swap ? OSSwapInt32(header->mappingCount) : header->mappingCount;
-       if ( mappingCount != 3 ) {
-               (*logProc)("dyld shared cache file %s has wrong mapping count\n", path);
-               close(fd);
-               return -1;
-       }
-
-       uint64_t slidePointersOffset = swap ? OSSwapInt64(header->slidePointersOffset) : header->slidePointersOffset;
-       uint64_t slidePointersSize = swap ? OSSwapInt64(header->slidePointersSize) : header->slidePointersSize;
-       if ( (slidePointersOffset == 0) || (slidePointersSize == 0) ) {
-               (*logProc)("dyld shared cache file %s is missing slide information\n", path);
-               close(fd);
-               return -1;
-       }
-       
-       // read slide info
-       void* slideInfo = malloc(slidePointersSize);
-       if ( slideInfo == NULL ) {
-               (*logProc)("malloc(%llu) failed\n", slidePointersSize);
-               close(fd);
-               return -1;
-       }
-       int64_t amountRead = pread(fd, slideInfo, slidePointersSize, slidePointersOffset);
-       if ( amountRead != (int64_t)slidePointersSize ) {
-               (*logProc)("slide info pread(fd, buf, %llu, %llu) failed\n", slidePointersSize, slidePointersOffset);
-               close(fd);
-               return -1;
-       }
-
-       // read all DATA 
-       const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)&buffer[mappingOffset];
-       uint64_t dataFileOffset = swap ? OSSwapInt64(mappings[1].fileOffset) : mappings[1].fileOffset;
-       uint64_t dataSize = swap ? OSSwapInt64(mappings[1].size) : mappings[1].size;
-       uint8_t* data = (uint8_t*)malloc(dataSize);
-       amountRead = pread(fd, data, dataSize, dataFileOffset);
-       if ( amountRead != (int64_t)dataSize ) {
-               (*logProc)("data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
-               close(fd);
-               return -1;
-       }
-       
-       // close read-only file
-       close(fd);
-       
-       // extract current slide
-       uint64_t headerDataUses;
-       if ( has64BitPointers ) {
-               headerDataUses = *((uint64_t*)data);
-               if ( swap ) 
-                       headerDataUses = OSSwapInt64(headerDataUses);
-       }
-       else {
-               uint32_t temp = *((uint32_t*)data);
-               if ( swap ) 
-                       temp = OSSwapInt32(temp);
-               headerDataUses = temp;
-       }
-       uint64_t textAddress = swap ? OSSwapInt64(mappings[0].address) : mappings[0].address;
-       uint32_t currentSlide = headerDataUses - textAddress;
-       (*logProc)("currentSlide=0x%08X\n", currentSlide);
-       
-       // find read-only space
-       uint64_t linkeditAddress = swap ? OSSwapInt64(mappings[2].address) : mappings[2].address;
-       uint64_t linkeditSize = swap ? OSSwapInt64(mappings[2].size) : mappings[2].size;
-       uint64_t linkeditEnd = linkeditAddress + linkeditSize;
-       uint64_t roSpace = endReadOnlySharedRegion - linkeditEnd;
-       (*logProc)("ro space=0x%08llX\n", roSpace);
-       
-       // find read-write space
-       uint64_t dataAddress = swap ? OSSwapInt64(mappings[1].address) : mappings[1].address;
-       uint64_t dataEnd = dataAddress + dataSize;
-       uint64_t rwSpace = endReadWriteSharedRegion - dataEnd;
-       (*logProc)("rw space=0x%08llX\n", rwSpace);
-       
-       // choose new random slide
-       uint32_t slideSpace = rwSpace;
-       if ( roSpace < rwSpace )
-               slideSpace = roSpace;
-       uint32_t newSlide = (arc4random() % slideSpace) & (-4096);
-       (*logProc)("newSlide=0x%08X\n", newSlide);
-       int32_t slideAdjustment = newSlide - currentSlide;
-       
-       // update DATA with slide info
-       uint64_t offsetInCacheFile = 0;
-       const uint8_t* infoStart = (uint8_t*)slideInfo;
-       const uint8_t* infoEnd = infoStart + slidePointersSize;
-       for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
-               uint64_t delta = 0;
-               uint32_t shift = 0;
-               bool more = true;
-               do {
-                       uint8_t byte = *p++;
-                       delta |= ((byte & 0x7F) << shift);
-                       shift += 7;
-                       if ( byte < 0x80 ) {
-                               offsetInCacheFile += delta;
-                               // verify in DATA range
-                               if ( (offsetInCacheFile < dataFileOffset) || (offsetInCacheFile > (dataFileOffset+dataSize)) ) {
-                                       (*logProc)("pointer offset 0x%llX outside DATA range\n", offsetInCacheFile);
-                                       return -1;
-                               }
-                               uint32_t offsetInData = offsetInCacheFile - dataFileOffset;
-                               if ( has64BitPointers ) {
-                                       uint64_t value64 = *((uint64_t*)(&data[offsetInData]));
-                                       if ( swap ) 
-                                               value64 = OSSwapInt64(value64);
-                                       value64 += slideAdjustment;
-                                       if ( swap ) 
-                                               value64 = OSSwapInt64(value64);
-                                       *((uint64_t*)(&data[offsetInData])) = value64;
-                               }
-                               else {
-                                       uint64_t value32 = *((uint32_t*)(&data[offsetInData]));
-                                       if ( swap ) 
-                                               value32 = OSSwapInt32(value32);
-                                       value32 += slideAdjustment;
-                                       if ( swap ) 
-                                               value32 = OSSwapInt32(value32);
-                                       *((uint32_t*)(&data[offsetInData])) = value32;
-                               }
-                               //(*logProc)("update pointer at offset 0x%08X", offsetInData);
-                               more = false;
-                       }
-               } while (more);
-       }
-       free(slideInfo);
-       slideInfo = NULL;
-       
-       // re-open cache file and overwrite DATA range
-       fd = open(path, O_RDWR, 0);
-       if ( fd == -1 ) {
-               (*logProc)("open(%s) failed, errno=%d\n", path, errno);
-               return -1;
-       }
-       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
-       uint64_t amountWrote = pwrite(fd, data, dataSize, dataFileOffset);
-       if ( amountWrote != dataSize ) {
-               (*logProc)("data pwrite(fd, buf, %llu, %llu) failed\n", data, dataSize);
-               close(fd);
-               return -1;
-       }
-       close(fd);
-       
-       // re-open and re-read to verify write
-       fd = open(path, O_RDONLY, 0);
-       if ( fd == -1 ) {
-               (*logProc)("verify open(%s) failed, errno=%d\n", path, errno);
-               return -1;
-       }
-       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
-       uint8_t* dataVerify = (uint8_t*)malloc(dataSize);
-       amountRead = pread(fd, dataVerify, dataSize, dataFileOffset);
-       if ( amountRead != (int64_t)dataSize ) {
-               (*logProc)("verify data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
-               close(fd);
-               return -1;
-       }
-       close(fd);
-       if ( memcmp(data, dataVerify, dataSize) != 0 ) {
-               (*logProc)("data update verification failed\n");
-               return -1;
-       }
-       free(data);
-       free(dataVerify);
-
-       
-       // success
-       return 0;
-}
-
-
-#if 0
-static void logger(const char* format, ...)
-{
-       va_list list;
-       va_start(list, format);
-       fprintf(stderr, "error: ");
-       vfprintf(stderr, format, list);
-}
-
-
-int main(int argc, const char* argv[])
-{
-       return update_dyld_shared_cache_load_address(argv[1], logger);
-}
-#endif
-
-
diff --git a/launch-cache/dsc_slider.h b/launch-cache/dsc_slider.h
deleted file mode 100644 (file)
index 4979562..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif 
-
-//
-// This function is called with a path to a dyld shared cache file.  It will update the shared cache file 
-// in place.  The update randomizes the load address when the shared cache file is later used by dyld.
-//
-// On success, the return value is zero.  
-// On failure the return value is non-zero and an explanation error was written to the logProc callback.
-//
-extern int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) );
-
-
-#ifdef __cplusplus
-}
-#endif 
index 42a1a139155e60e2c5f53b753b5a18a13b232ba7..70d897cb7e7f9ed165239e13a1934e8426872b6c 100644 (file)
@@ -31,7 +31,7 @@
 
 struct dyld_cache_header
 {
-       char            magic[16];                              // e.g. "dyld_v0     ppc"
+       char            magic[16];                              // e.g. "dyld_v0    i386"
        uint32_t        mappingOffset;                  // file offset to first dyld_cache_mapping_info
        uint32_t        mappingCount;                   // number of dyld_cache_mapping_info entries
        uint32_t        imagesOffset;                   // file offset to first dyld_cache_image_info
index d82674af33f90c4d1d27355287993101a190e443..b0b69182cc1aee5591472dc1889cbb78939f5c51 100644 (file)
@@ -78,14 +78,16 @@ static const char* default_shared_cache_path() {
        return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "i386";
 #elif __x86_64__ 
        return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
-#elif __ppc__ 
-       return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "rosetta";
 #elif __ARM_ARCH_5TEJ__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv5";
 #elif __ARM_ARCH_6K__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv6";
 #elif __ARM_ARCH_7A__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7";
+#elif __ARM_ARCH_7F__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7f";
+#elif __ARM_ARCH_7K__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7k";
 #else
        #error unsupported architecture
 #endif
@@ -137,14 +139,17 @@ void list_dependencies(const char *dylib, void *headerAddr, uint8_t print_dylib_
                        uint32_t current_vers = dylib_cmd->current_version();
                        
             if (print_dylib_versions) {
-                printf("\t%s (compatibility version %u.%u.%u, current version %u.%u.%u)\n", 
-                       name, 
+                printf("\t%s", name);
+                if ( compat_vers != 0xFFFFFFFF )
+                    printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n", 
                        (compat_vers >> 16),
                        (compat_vers >> 8) & 0xff,
                        (compat_vers) & 0xff,
                        (current_vers >> 16),
                        (current_vers >> 8) & 0xff,
                        (current_vers) & 0xff);
+                else
+                    printf("\n");
             } else {
                 printf("\t%s\n", name);
             }                  
@@ -417,7 +422,9 @@ int main (int argc, char **argv) {
                const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)mapped_cache;
                if (   (strcmp(header->magic(), "dyld_v1  x86_64") != 0)
                        && (strcmp(header->magic(), "dyld_v1   armv6") != 0)
-                       && (strcmp(header->magic(), "dyld_v1   armv7") != 0) ) {
+                       && (strcmp(header->magic(), "dyld_v1   armv7") != 0) 
+                       && (strcmp(header->magic(), "dyld_v1  armv7f") != 0) 
+                       && (strcmp(header->magic(), "dyld_v1  armv7k") != 0) ) {
                        fprintf(stderr, "Error: unrecognized dyld shared cache magic or arch does not support sliding\n");
                        exit(1);
                }
@@ -449,14 +456,16 @@ int main (int argc, char **argv) {
                        callback = segment_callback<x86>;
                else if ( strcmp((char*)mapped_cache, "dyld_v1  x86_64") == 0 ) 
                        callback = segment_callback<x86_64>;
-               else if ( strcmp((char*)mapped_cache, "dyld_v1     ppc") == 0 ) 
-                       callback = segment_callback<ppc>;
                else if ( strcmp((char*)mapped_cache, "dyld_v1   armv5") == 0 ) 
                        callback = segment_callback<arm>;
                else if ( strcmp((char*)mapped_cache, "dyld_v1   armv6") == 0 ) 
                        callback = segment_callback<arm>;
                else if ( strcmp((char*)mapped_cache, "dyld_v1   armv7") == 0 ) 
                        callback = segment_callback<arm>;
+               else if ( strcmp((char*)mapped_cache, "dyld_v1  armv7f") == 0 ) 
+                       callback = segment_callback<arm>;
+               else if ( strcmp((char*)mapped_cache, "dyld_v1  armv7k") == 0 ) 
+                       callback = segment_callback<arm>;
                else {
                        fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
                        exit(1);
index c7a3874b9a11d379d092e722768eca189bea818b..ac9cc1ccc006a8be19b2a00e3d8b5e5dda11bb25 100644 (file)
@@ -59,9 +59,9 @@
 #include "CacheFileAbstraction.hpp"
 
 #define SELOPT_WRITE
-#include <objc/objc-selopt.h>
+#include "objc-shared-cache.h"
 
-#define FIRST_DYLIB_TEXT_OFFSET 0x5000
+#define FIRST_DYLIB_TEXT_OFFSET 0x7000
 #define FIRST_DYLIB_DATA_OFFSET 0x1000
 
 #ifndef LC_FUNCTION_STARTS
@@ -109,7 +109,8 @@ public:
        static void                     addRoot(const char* vpath, const std::set<ArchPair>& archs);
        static void                     findSharedDylibs(ArchPair ap);
        static ArchGraph*       graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
-       static void                     setFileSystemRoot(const char* root, bool usesOverlay) { fgFileSystemRoot = root; fgUsesOverlay = usesOverlay; }
+       static void                     setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
+       static void                     setFileSystemOverlay(const char* overlay) { fgFileSystemOverlay = overlay; }
        static const char*      archName(ArchPair ap);
        
        ArchPair                                                                                        getArchPair() { return fArchPair; }
@@ -151,7 +152,7 @@ private:
 
        static std::map<ArchPair, ArchGraph*>   fgPerArchGraph;
        static const char*                                              fgFileSystemRoot;
-       static bool                                                             fgUsesOverlay;
+       static const char*                                              fgFileSystemOverlay;
        
        ArchPair                                                                        fArchPair;
        std::set<DependencyNode*>                                       fRoots;
@@ -161,7 +162,7 @@ private:
 };
 std::map<ArchPair, ArchGraph*>         ArchGraph::fgPerArchGraph;
 const char*                                                    ArchGraph::fgFileSystemRoot = "";
-bool                                                           ArchGraph::fgUsesOverlay = false;
+const char*                                                    ArchGraph::fgFileSystemOverlay = "";
 
 void ArchGraph::addArchPair(ArchPair ap)
 {
@@ -171,28 +172,30 @@ void ArchGraph::addArchPair(ArchPair ap)
 
 void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
 {
-       char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
+       //fprintf(stderr, "addRoot(%s)\n", vpath);
+       char completePath[MAXPATHLEN];
        const char* path = NULL;
-       if ( strlen(fgFileSystemRoot) == 0 ) {
-               path = vpath;
+       // check -overlay path first
+       if ( fgFileSystemOverlay[0] != '\0' ) {
+               strcpy(completePath, fgFileSystemOverlay);
+               strcat(completePath, vpath);    // assumes vpath starts with '/'
+               struct stat stat_buf;
+               if ( stat(completePath, &stat_buf) == 0 )
+                       path = completePath;
        }
-       else {
+       // if not found in overlay, check for -root
+       if ( (path == NULL) && (fgFileSystemRoot[0] != '\0') ) {
                strcpy(completePath, fgFileSystemRoot);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
-               if ( fgUsesOverlay ) {
-                       // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
-                       struct stat stat_buf;
-                       if ( stat(completePath, &stat_buf) == 0 )
-                               path = completePath;
-                       else
-                               path = vpath;
-               }
-               else {
-                       // using -root means alway redirect /usr/lib to /rootpath/usr/lib
+               struct stat stat_buf;
+               if ( stat(completePath, &stat_buf) == 0 )
                        path = completePath;
-               }
        }
+       if ( path == NULL ) 
+               path = vpath;
+       
        try {
+               //fprintf(stderr, "    UniversalMachOLayout::find(%s)\n", path);
                const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &onlyArchs);
                for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
                        try {
@@ -229,54 +232,59 @@ void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
                node->markNeededByRoot(NULL);
 }
 
-// a virtual path does not have the fgFileSystemRoot prefix
 // a virtual path does not have the fgFileSystemRoot prefix
 ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
 {
-       if ( fgFileSystemRoot == NULL ) {
-               return this->getNode(vpath);
-       }
-       else {
-               char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
-               strcpy(completePath, fgFileSystemRoot);
+       //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
+       char completePath[MAXPATHLEN];
+       if ( fgFileSystemOverlay[0] != '\0' ) {
+               // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
+               strcpy(completePath, fgFileSystemOverlay);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
-               if ( fgUsesOverlay ) {
-                       // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
-                       struct stat stat_buf;
-                       if ( stat(completePath, &stat_buf) == 0 )
-                               return this->getNode(completePath);
-                       else {
-                               // <rdar://problem/9279770> support when install name is a symlink
-                               if ( (lstat(vpath, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
-                                       // requested path did not exist in /overlay, but leaf of path is a symlink in /
-                                       char pathInSymLink[MAXPATHLEN];
-                                       size_t res = readlink(vpath, pathInSymLink, sizeof(pathInSymLink));
-                                       if ( res != -1 ) {
-                                               pathInSymLink[res] = '\0';
-                                               if ( pathInSymLink[0] != '/' ) {
-                                                       char symFullPath[MAXPATHLEN];
-                                                       strcpy(symFullPath, vpath);
-                                                       char* lastSlash = strrchr(symFullPath, '/');
-                                                       if ( lastSlash != NULL ) {
-                                                               strcpy(lastSlash+1, pathInSymLink);
-                                                               // (re)try looking for what symlink points to, but in /overlay
-                                                               return this->getNodeForVirtualPath(symFullPath);
-                                                       }
-                                               } 
-                                       }
+               struct stat stat_buf;
+               if ( stat(completePath, &stat_buf) == 0 )
+                       return this->getNode(completePath);
+               else {
+                       // <rdar://problem/9279770> support when install name is a symlink
+                       const char* pathToSymlink = vpath;
+                       if ( fgFileSystemRoot[0] != '\0' ) {
+                               strcpy(completePath, fgFileSystemRoot);
+                               strcat(completePath, vpath);
+                               pathToSymlink = completePath;
+                       }
+                       if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
+                               // requested path did not exist in /overlay, but leaf of path is a symlink in /
+                               char pathInSymLink[MAXPATHLEN];
+                               size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
+                               if ( res != -1 ) {
+                                       pathInSymLink[res] = '\0';
+                                       if ( pathInSymLink[0] != '/' ) {
+                                               char symFullPath[MAXPATHLEN];
+                                               strcpy(symFullPath, vpath);
+                                               char* lastSlash = strrchr(symFullPath, '/');
+                                               if ( lastSlash != NULL ) {
+                                                       strcpy(lastSlash+1, pathInSymLink);
+                                                       // (re)try looking for what symlink points to, but in /overlay
+                                                       return this->getNodeForVirtualPath(symFullPath);
+                                               }
+                                       } 
                                }
-                               return this->getNode(vpath);
                        }
                }
-               else {
-                       // using -root means always use /rootpath/usr/lib
-                       return this->getNode(completePath);
-               }
        }
+       if ( fgFileSystemRoot[0] != '\0' ) {
+               // using -root means always use /rootpath/usr/lib
+               strcpy(completePath, fgFileSystemRoot);
+               strcat(completePath, vpath);    // assumes vpath starts with '/'
+               return this->getNode(completePath);
+       }
+       // not found in -overlay or -root not used
+       return this->getNode(vpath);
 }
 
 ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
 {
+       //fprintf(stderr, "getNode(%s)\n", path);
        // look up supplied path to see if node already exists
        PathToNode::iterator pos = fNodes.find(path);
        if ( pos != fNodes.end() )
@@ -328,9 +336,13 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
                        fNodes[node->getLayout()->getID().name] = node;
                // update fAliasesMap with symlinks found
                const char* aliasPath = realPath;
-               if ( (fgFileSystemRoot != NULL) && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+               if ( (fgFileSystemRoot != NULL) && (fgFileSystemRoot[0] != '\0') && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
                        aliasPath = &realPath[strlen(fgFileSystemRoot)];
                }
+               // <rdar://problem/11192810> Too many aliases in -overlay mode
+               if ( (fgFileSystemOverlay != NULL) && (fgFileSystemOverlay[0] != '\0') && (strncmp(realPath, fgFileSystemOverlay, strlen(fgFileSystemOverlay)) == 0) ) {
+                       aliasPath = &realPath[strlen(fgFileSystemOverlay)];
+               }
                if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
                        if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
                                fAliasesMap[strdup(aliasPath)] = node->getLayout()->getID().name;
@@ -402,7 +414,7 @@ void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* m
                                        fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
                        }
                        catch (const char* msg) {
-                               if ( it->weakImport && ! fLayout->hasSplitSegInfo() ) {
+                               if ( it->weakImport || ! fLayout->hasSplitSegInfo() ) {
                                        // ok to ignore missing weak imported dylibs from things that are
                                        // not going to be in the dyld shared cache
                                }
@@ -476,8 +488,6 @@ void ArchGraph::findSharedDylibs(ArchPair ap)
 const char*    ArchGraph::archName(ArchPair ap)
 {
        switch ( ap.arch ) {
-               case CPU_TYPE_POWERPC:
-                       return "ppc";
                case CPU_TYPE_I386:
                        return "i386";
                case CPU_TYPE_X86_64:
@@ -494,6 +504,10 @@ const char*        ArchGraph::archName(ArchPair ap)
                                        return "arm-xscale";
                                case CPU_SUBTYPE_ARM_V7:
                                        return "armv7";
+                               case CPU_SUBTYPE_ARM_V7F:
+                                       return "armv7f";
+                               case CPU_SUBTYPE_ARM_V7K:
+                                       return "armv7k";
                                default:
                                        return "arm";
                        }
@@ -554,6 +568,9 @@ bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, c
                                if ( nodes.find(realPath) != nodes.end() )
                                        continue;
                        }
+                       // handle weak imported dylibs not found
+                       if ( dit->weakImport )
+                               continue;
                        shareableMap[layout] = false;
                        char* msg;
                        asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be found", layout->getID().name, dit->name);
@@ -582,8 +599,9 @@ template <typename A>
 class SharedCache
 {
 public:
-                                                       SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress);
-       bool                                    update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex, 
+                                                       SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir,
+                                                                                       bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress);
+       bool                                    update(bool force, bool optimize, bool deleteExistingFirst, int archIndex, 
                                                                                int archCount, bool keepSignatures);
        static const char*              cacheFileSuffix(bool optimized, const char* archName);
 
@@ -595,6 +613,8 @@ public:
        uint64_t                                cacheFileOffsetForVMAddress(uint64_t addr) const;
        uint64_t                                VMAddressForCacheFileOffset(uint64_t addr) const;
 
+       static const char*              archName();
+
 private:
        typedef typename A::P                   P;
     typedef typename A::P::E           E;
@@ -607,7 +627,6 @@ private:
 
        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();
@@ -627,6 +646,12 @@ private:
                bool operator()(const LayoutInfo& left, const LayoutInfo& right) 
                                { return (strcmp(left.layout->getID().name, right.layout->getID().name) < 0); }
        };
+       
+       struct ByAddressSorter {
+               bool operator()(const LayoutInfo& left, const LayoutInfo& right) { 
+                       return (left.layout->getSegments()[0].newAddress() < right.layout->getSegments()[0].newAddress()); 
+               }
+       };
 
     struct ByCStringSectionSizeSorter {
         bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
@@ -690,6 +715,8 @@ private:
        uint32_t                                                        fSizeOfOldStringPoolInCombinedLinkedit;
        uint32_t                                                        fOffsetOfFunctionStartsInCombinedLinkedit;
        uint32_t                                                        fSizeOfFunctionStartsInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfDataInCodeInCombinedLinkedit;
+       uint32_t                                                        fSizeOfDataInCodeInCombinedLinkedit;
        uint32_t                                                        fLinkEditsTotalOptimizedSize;
 };
 
@@ -783,44 +810,37 @@ public:
 
 
        
-template <>     cpu_type_t     SharedCache<ppc>::arch()        { return CPU_TYPE_POWERPC; }
 template <>     cpu_type_t     SharedCache<x86>::arch()        { return CPU_TYPE_I386; }
 template <>     cpu_type_t     SharedCache<x86_64>::arch()     { return CPU_TYPE_X86_64; }
 template <>     cpu_type_t     SharedCache<arm>::arch()        { return CPU_TYPE_ARM; }
 
-template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlyStartAddress()    { return 0x90000000; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionReadOnlyStartAddress()    { return 0x90000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlyStartAddress()    { return 0x30000000; }
 
-template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionWritableStartAddress()    { return 0xAC000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionWritableStartAddress()    { return 0x3E000000; }
 
-template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlySize()                    { return 0x10000000; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionReadOnlySize()                    { return 0x1C000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionReadOnlySize()                 { return 0x40000000; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlySize()                    { return 0x0E000000; }
 
-template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableSize()                    { return 0x10000000; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionWritableSize()                    { return 0x04000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableSize()                 { return 0x10000000; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionWritableSize()                    { return 0x02000000; }
 
 
-template <>     const char*    SharedCache<ppc>::archName()    { return "ppc"; }
 template <>     const char*    SharedCache<x86>::archName()    { return "i386"; }
 template <>     const char*    SharedCache<x86_64>::archName() { return "x86_64"; }
 template <>     const char*    SharedCache<arm>::archName()    { return "arm"; }
 
-template <>     const char*    SharedCache<ppc>::cacheFileSuffix(bool optimized, const char*)  { return optimized ? "ppc" : "rosetta"; }
 template <>     const char*    SharedCache<x86>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 template <>     const char*    SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
 template <>     const char*    SharedCache<arm>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 
 template <typename A>
-SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress) 
+SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress) 
   : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true), 
        fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
        fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
@@ -830,7 +850,8 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
        fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
        fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
-       fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0)
+       fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
+       fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0)
 {
        if ( fArchGraph->getArchPair().arch != arch() )
                throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
@@ -857,29 +878,50 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        }
 
        // create path to cache file
-       char cachePathNonOverlay[1024];
-       strcpy(cachePathNonOverlay, cacheDir);
-       if ( cachePathNonOverlay[strlen(cachePathNonOverlay)-1] != '/' )
-               strcat(cachePathNonOverlay, "/");
-       strcat(cachePathNonOverlay, DYLD_SHARED_CACHE_BASE_NAME);
-       strcat(cachePathNonOverlay, cacheFileSuffix(optimize, fArchGraph->archName()));
-       char cachePath[1024];
-       strcpy(cachePath, rootPath);
-       strcat(cachePath, "/");
-       strcat(cachePath, cachePathNonOverlay);
-       if ( !overlay && (rootPath[0] != '\0') )
-               fCacheFilePath = strdup(cachePathNonOverlay);
-       else
+       char cachePathCanonical[MAXPATHLEN];
+       strcpy(cachePathCanonical, cacheDir);
+       if ( cachePathCanonical[strlen(cachePathCanonical)-1] != '/' )
+               strcat(cachePathCanonical, "/");
+       strcat(cachePathCanonical, DYLD_SHARED_CACHE_BASE_NAME);
+       strcat(cachePathCanonical, cacheFileSuffix(optimize, fArchGraph->archName()));
+       char cachePath[MAXPATHLEN];
+       if ( explicitCacheDir ) {
+               fCacheFilePath = strdup(cachePathCanonical);
+       }
+       else if ( overlayPath[0] != '\0' ) {
+               strcpy(cachePath, overlayPath);
+               strcat(cachePath, "/");
+               strcat(cachePath, cachePathCanonical);
+               fCacheFilePath = strdup(cachePath);
+       }
+       else if ( rootPath[0] != '\0' ) {
+               strcpy(cachePath, rootPath);
+               strcat(cachePath, "/");
+               strcat(cachePath, cachePathCanonical);
                fCacheFilePath = strdup(cachePath);
-       if ( overlay ) {
+       }
+       else {
+               fCacheFilePath = strdup(cachePathCanonical);
+       }
+       if ( overlayPath[0] != '\0' ) {
                // in overlay mode if there already is a cache file in the overlay
-               // check if it is up to date.  If there is no file, check if
-               // the one in the boot volume is up to date.
+               // check if it is up to date.  
                struct stat stat_buf;
-               if ( stat(fCacheFilePath, &stat_buf) == 0 ) 
+               if ( stat(fCacheFilePath, &stat_buf) == 0 ) {
                        fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
-               else
-                       fExistingIsNotUpToDate = this->notUpToDate(cachePathNonOverlay, aliasCount);
+               }
+               else if ( rootPath[0] != '\0' ) {
+                       // using -root and -overlay, but no cache file in overlay, check one in -root
+                       char cachePathRoot[MAXPATHLEN];
+                       strcpy(cachePathRoot, rootPath);
+                       strcat(cachePathRoot, "/");
+                       strcat(cachePathRoot, cachePathCanonical);
+                       fExistingIsNotUpToDate = this->notUpToDate(cachePathRoot, aliasCount);
+               }
+               else {
+                       // uisng -overlay, but no cache file in overlay, check one in boot volume
+                       fExistingIsNotUpToDate = this->notUpToDate(cachePathCanonical, aliasCount);
+               }
        }
        else {
                fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
@@ -955,13 +997,6 @@ uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddres
        return proposedNewAddress;
 }
 
-template <>
-uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
-{
-       // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
-       return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
-}
-
 
 template <typename A>
 void SharedCache<A>::assignNewBaseAddresses(bool verify)
@@ -1012,7 +1047,6 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
                                }
                                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);
@@ -1296,7 +1330,7 @@ bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
        (void)fcntl(fd, F_NOCACHE, 1);
     ssize_t readResult = pread(fd, mappingAddr, cacheFileSize, 0);
     if ( readResult != cacheFileSize )
-        throw "can't read existing cache file";
+        throwf("can't read all of existing cache file (%lu of %u): %s", readResult, cacheFileSize, path);
        ::close(fd);
 
        // validate it
@@ -1403,6 +1437,7 @@ public:
                void                                                            copyExternalRelocations(uint32_t& offset);
                void                                                            copyIndirectSymbolTable(uint32_t& offset);
                void                                                            copyFunctionStarts(uint32_t& offset);
+               void                                                            copyDataInCode(uint32_t& offset);
                void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
                                                                                                                                uint32_t linkEditsFileOffset, bool keepSignatures);
        
@@ -1422,6 +1457,7 @@ private:
        macho_dyld_info_command<P>*                                     fDyldInfo;
        macho_dysymtab_command<P>*                                      fDynamicSymbolTable;
        macho_linkedit_data_command<P>*                         fFunctionStarts;
+       macho_linkedit_data_command<P>*                         fDataInCode;
        macho_symtab_command<P>*                                        fSymbolTableLoadCommand;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
@@ -1445,6 +1481,7 @@ private:
        uint32_t                                                                        fExternalRelocationsOffsetIntoNewLinkEdit;
        uint32_t                                                                        fIndirectSymbolTableOffsetInfoNewLinkEdit;
        uint32_t                                                                        fFunctionStartsOffsetInNewLinkEdit;
+       uint32_t                                                                        fDataInCodeOffsetInNewLinkEdit;
 };
 
 
@@ -1452,7 +1489,8 @@ private:
 template <typename A>
 LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache<A>& sharedCache, uint8_t* newLinkEdit, StringPool& stringPool)
  :     fSharedCache(sharedCache), fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
-       fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
+       fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fDataInCode(NULL), 
+       fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
        fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
        fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
        fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
@@ -1462,7 +1500,7 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, co
        fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
        fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
        fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
-       fFunctionStartsOffsetInNewLinkEdit(0)
+       fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0)
        
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
@@ -1497,6 +1535,8 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, co
                                break;
                        case LC_FUNCTION_STARTS:
                                fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
+                       case LC_DATA_IN_CODE:
+                               fDataInCode = (macho_linkedit_data_command<P>*)cmd;
                                break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
@@ -1674,6 +1714,17 @@ void LinkEditOptimizer<A>::copyFunctionStarts(uint32_t& offset)
        }
 }
 
+template <typename A>
+void LinkEditOptimizer<A>::copyDataInCode(uint32_t& offset)
+{      
+       if ( fDataInCode != NULL ) {
+               fDataInCodeOffsetInNewLinkEdit = offset;
+               memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fDataInCode->dataoff()], fDataInCode->datasize());
+               offset += fDataInCode->datasize();
+       }
+}
+
+
 template <typename A>
 void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
 {      
@@ -1772,6 +1823,10 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
        if ( fFunctionStarts != NULL ) {
                fFunctionStarts->set_dataoff(linkEditsFileOffset+fFunctionStartsOffsetInNewLinkEdit);
        }
+       // update data-in-code info
+       if ( fDataInCode != NULL ) {
+               fDataInCode->set_dataoff(linkEditsFileOffset+fDataInCodeOffsetInNewLinkEdit);
+       }
        
        // now remove load commands no longer needed
        const macho_load_command<P>* srcCmd = cmds;
@@ -1781,6 +1836,7 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
                uint32_t cmdSize = srcCmd->cmdsize();
                switch ( srcCmd->cmd() ) {
                        case LC_SEGMENT_SPLIT_INFO:
+                       case LC_DYLIB_CODE_SIGN_DRS:
                                // don't copy
                                break;
                        case LC_CODE_SIGNATURE:
@@ -1882,6 +1938,13 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
        }
        fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit;
 
+       // copy data-in-code info
+       fOffsetOfDataInCodeInCombinedLinkedit = offset;
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyDataInCode(offset);
+       }
+       fSizeOfDataInCodeInCombinedLinkedit = offset - fOffsetOfDataInCodeInCombinedLinkedit;
+
        // copy indirect symbol tables
        fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
@@ -1932,7 +1995,6 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
 }
 
 
-
 template <typename A>
 class ObjCSelectorUniquer
 {
@@ -1966,16 +2028,73 @@ public:
     size_t count() const { return fCount; }
 };
 
+
+template <typename A>
+class ClassListBuilder
+{
+private:
+    typedef typename A::P P;
+
+    objc_opt::string_map fClassNames;
+    objc_opt::class_map fClasses;
+    size_t fCount;
+    HeaderInfoOptimizer<A>& fHinfos;
+
+public:
+
+    ClassListBuilder(HeaderInfoOptimizer<A>& hinfos)
+        : fClassNames()
+        , fClasses()
+        , fCount(0)
+        , fHinfos(hinfos)
+    { }
+
+    void visitClass(SharedCache<A>* cache, 
+                    const macho_header<P>* header,
+                    objc_class_t<A>* cls) 
+    {
+        if (cls->isMetaClass(cache)) return;
+
+        const char *name = cls->getName(cache);
+        uint64_t name_vmaddr = cache->VMAddressForMappedAddress(name);
+        uint64_t cls_vmaddr = cache->VMAddressForMappedAddress(cls);
+        uint64_t hinfo_vmaddr = cache->VMAddressForMappedAddress(fHinfos.hinfoForHeader(cache, header));
+        fClassNames.insert(objc_opt::string_map::value_type(name, name_vmaddr));
+        fClasses.insert(objc_opt::class_map::value_type(name, std::pair<uint64_t, uint64_t>(cls_vmaddr, hinfo_vmaddr)));
+        fCount++;
+    }
+
+    objc_opt::string_map& classNames() { 
+        return fClassNames;
+    }
+
+    objc_opt::class_map& classes() { 
+        return fClasses;
+    }
+
+    size_t count() const { return fCount; }
+};
+
+
+static int percent(size_t num, size_t denom) {
+    if (denom) return (int)(num / (double)denom * 100);
+    else return 100;
+}
+
 template <typename A>
 void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
 {
     const char *err;
-    size_t headerSize = sizeof(objc_opt::objc_opt_t);
 
     if ( verbose ) {
         fprintf(stderr, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
     }
 
+    size_t headerSize = P::round_up(sizeof(objc_opt::objc_opt_t));
+    if (headerSize != sizeof(objc_opt::objc_opt_t)) {
+               warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
+    }
+
     // Find libobjc's empty sections to fill in
     const macho_section<P> *optROSection = NULL;
     const macho_section<P> *optRWSection = NULL;
@@ -1983,9 +2102,6 @@ void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
         if ( strstr(it->layout->getFilePath(), "libobjc") != NULL ) {
                        const macho_header<P>* mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
                        optROSection = mh->getSection("__TEXT", "__objc_opt_ro");
-                       // __objc_selopt is old name for __objc_opt_ro
-                       if ( optROSection == NULL )
-                               optROSection = mh->getSection("__TEXT", "__objc_selopt");
                        optRWSection = mh->getSection("__DATA", "__objc_opt_rw");
                        break;
                }
@@ -1996,17 +2112,62 @@ void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
                return;
        }
        
-       objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t*)mappedAddressForVMAddress(optROSection->addr());
-       if (optROSection->size() < headerSize) {
+       if ( optRWSection == NULL ) {
+               warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
+               return;
+       }
+
+       uint8_t* optROData = (uint8_t*)mappedAddressForVMAddress(optROSection->addr());
+    size_t optRORemaining = optROSection->size();
+
+       uint8_t* optRWData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr());
+    size_t optRWRemaining = optRWSection->size();
+       
+       if (optRORemaining < headerSize) {
                warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
                return;
        }
+       objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t *)optROData;
+    optROData += headerSize;
+    optRORemaining -= headerSize;
 
        if (E::get32(optROHeader->version) != objc_opt::VERSION) {
                warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
                return;
        }
 
+    // Write nothing to optROHeader until everything else is written.
+    // If something fails below, libobjc will not use the section.
+
+    // Find objc-containing dylibs
+    std::vector<LayoutInfo> objcDylibs;
+    for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+        macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        if (mh->getSection("__DATA", "__objc_imageinfo")  ||  mh->getSegment("__OBJC")) {
+            objcDylibs.push_back(*it);
+        }
+    }
+
+    // Build image list
+
+    // This is SAFE: the binaries themselves are unmodified.
+
+    std::vector<LayoutInfo> addressSortedDylibs = objcDylibs;
+    std::sort(addressSortedDylibs.begin(), addressSortedDylibs.end(), ByAddressSorter());
+
+    uint64_t hinfoVMAddr = optRWSection->addr() + optRWSection->size() - optRWRemaining;
+    HeaderInfoOptimizer<A> hinfoOptimizer;
+    err = hinfoOptimizer.init(objcDylibs.size(), optRWData, optRWRemaining);
+    if (err) {
+               warn(archName(), err);
+               return;
+    }
+    for(typename std::vector<LayoutInfo>::const_iterator it = addressSortedDylibs.begin(); it != addressSortedDylibs.end(); ++it) {
+        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        hinfoOptimizer.update(this, mh, pointersInData);
+    }
+
+
     // Update selector references and build selector list
 
     // This is SAFE: if we run out of room for the selector table, 
@@ -2015,102 +2176,128 @@ void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
     // Heuristic: choose selectors from libraries with more cstring data first.
     // This tries to localize selector cstring memory.
     ObjCSelectorUniquer<A> uniq(this);
-    std::vector<LayoutInfo> sortedDylibs = fDylibs;
-    std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
+    std::vector<LayoutInfo> sizeSortedDylibs = objcDylibs;
+    std::sort(sizeSortedDylibs.begin(), sizeSortedDylibs.end(), ByCStringSectionSizeSorter());
 
     SelectorOptimizer<A, ObjCSelectorUniquer<A> > selOptimizer(uniq);
-       for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
+       for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
         const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
         LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
         selOptimizer.optimize(this, mh);
        }
 
-    if ( verbose ) {
-        fprintf(stderr, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq.strings().size());
+    uint64_t seloptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
+    objc_opt::objc_selopt_t *selopt = new(optROData) objc_opt::objc_selopt_t;
+    err = selopt->write(seloptVMAddr, optRORemaining, uniq.strings());
+    if (err) {
+        warn(archName(), err);
+        return;
     }
+    optROData += selopt->size();
+    optRORemaining -= selopt->size();
+    selopt->byteswap(E::little_endian), selopt = NULL;
 
-    // Write selector table in read-only data.
-    size_t selTableOffset = P::round_up(headerSize);
-    size_t selTableSize;
-    objc_opt::objc_selopt_t *seloptData = (objc_opt::objc_selopt_t *)
-        mappedAddressForVMAddress(optROSection->addr() + selTableOffset);
-    err = objc_opt::write_selopt(seloptData, 
-                                 optROSection->addr() + selTableOffset, 
-                                 optROSection->size() - selTableOffset, 
-                                 uniq.strings(), 
-                                 E::little_endian, &selTableSize);
+
+    // Build class table.
+
+    // This is SAFE: the binaries themselves are unmodified.
+
+    ClassListBuilder<A> classes(hinfoOptimizer);
+    ClassWalker< A, ClassListBuilder<A> > classWalker(classes);
+       for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        classWalker.walk(this, mh);
+       }
+
+    uint64_t clsoptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
+    objc_opt::objc_clsopt_t *clsopt = new(optROData) objc_opt::objc_clsopt_t;
+    err = clsopt->write(clsoptVMAddr, optRORemaining, 
+                        classes.classNames(), classes.classes(), verbose);
     if (err) {
         warn(archName(), err);
         return;
     }
+    optROData += clsopt->size();
+    optRORemaining -= clsopt->size();
+    size_t duplicateCount = clsopt->duplicateCount();
+    clsopt->byteswap(E::little_endian), clsopt = NULL;
+
+
+    // Sort method lists.
+
+    // This is SAFE: modified binaries are still usable as unsorted lists.
+    // This must be done AFTER uniquing selectors.
+
+    MethodListSorter<A> methodSorter;
+    for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+        macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        methodSorter.optimize(this, mh);
+    }
+
+
+    // Repair ivar offsets.
+
+    // This is SAFE: the runtime always validates ivar offsets at runtime.
+
+    IvarOffsetOptimizer<A> ivarOffsetOptimizer;
+       for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        ivarOffsetOptimizer.optimize(this, mh);
+       }
+    
+
+    // Success. Mark dylibs as optimized.
+       for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+        const macho_section<P> *imageInfoSection;
+        imageInfoSection = mh->getSection("__DATA", "__objc_imageinfo");
+        if (!imageInfoSection) {
+            imageInfoSection = mh->getSection("__OBJC", "__image_info");
+        }
+        if (imageInfoSection) {
+            objc_image_info<A> *info = (objc_image_info<A> *)
+                mappedAddressForVMAddress(imageInfoSection->addr());
+            info->setOptimizedByDyld();
+        }
+    }
+
+
+    // Success. Update RO header last.
+    E::set32(optROHeader->selopt_offset, seloptVMAddr - optROSection->addr());
+    E::set32(optROHeader->clsopt_offset, clsoptVMAddr - optROSection->addr());
+    E::set32(optROHeader->headeropt_offset, hinfoVMAddr - optROSection->addr());
 
     if ( verbose ) {
-        size_t totalSize = headerSize + selTableSize;
+        size_t roSize = optROSection->size() - optRORemaining;
+        size_t rwSize = optRWSection->size() - optRWRemaining;
         fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
                 "(%d%%) used in libobjc read-only optimization section\n", 
-                archName(), totalSize, optROSection->size(), 
-                (int)(totalSize / (double)optROSection->size() * 100));
+                archName(), roSize, optROSection->size(), 
+                percent(roSize, optROSection->size()));
+        fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
+                "(%d%%) used in libobjc read/write optimization section\n", 
+                archName(), rwSize, optRWSection->size(), 
+                percent(rwSize, optRWSection->size()));
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "uniqued %zu selectors\n", 
+                archName(), uniq.strings().size());
         fprintf(stderr, "update_dyld_shared_cache: for %s, "
                 "updated %zu selector references\n", 
                 archName(), uniq.count());
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "updated %zu ivar offsets\n", 
+                archName(), ivarOffsetOptimizer.optimized());
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "sorted %zu method lists\n", 
+                archName(), methodSorter.optimized());
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "recorded %zu classes (%zu duplicates)\n", 
+                archName(), classes.classNames().size(), duplicateCount);
         fprintf(stderr, "update_dyld_shared_cache: for %s, "
                 "wrote objc metadata optimization version %d\n", 
                 archName(), objc_opt::VERSION);
     }
 
-       // if r/w section exists in libojc attempt to optimize categories into classes
-       if ( optRWSection != NULL ) {
-               // Attach categories to classes in the same framework. 
-               // Build aggregated (but unsorted) method lists in read-write data.
-
-               // This is SAFE: if we run out of room while attaching categories in 
-               // a binary then previously-edited binaries are still valid. (This assumes 
-               // each binary is processed all-or-nothing, which CategoryAttacher does.)
-               // This must be done AFTER uniquing selectors.
-               // This must be done BEFORE sorting method lists.
-               
-               size_t categoryOffset = 0;
-               uint8_t *categoryData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr() + categoryOffset);
-               CategoryAttacher<A> categoryAttacher(categoryData, optRWSection->size() - categoryOffset);
-               for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
-                       macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
-                       err = categoryAttacher.optimize(this, mh, pointersInData);
-                       if (err) {
-                               warn(archName(), err);
-                               return;
-                       }
-               }    
-               size_t categorySize = categoryAttacher.bytesUsed();
-
-
-               // Sort method lists.
-               
-               // This is SAFE: modified binaries are still usable as unsorted lists.
-               // This must be done AFTER uniquing selectors.
-               // This must be done AFTER attaching categories.
-
-               MethodListSorter<A> methodSorter;
-               for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
-                       macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
-                       methodSorter.optimize(this, mh);
-               }
-
-               if ( verbose ) {
-                       size_t totalRWSize = categorySize;
-                       fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
-                "(%d%%) used in libobjc read-write optimization section\n", 
-                archName(), totalRWSize, optRWSection->size(), 
-                (int)(totalRWSize / (double)optRWSection->size() * 100));
-                       fprintf(stderr, "update_dyld_shared_cache: for %s, "
-                "attached %zu categories (%zd bytes used)\n", 
-                archName(), categoryAttacher.count(), 
-                categoryAttacher.bytesUsed());
-               }
-       }
-
-    // Success. Update RO header last
-    E::set32(optROHeader->selopt_offset, headerSize);
-
     return;
 }
 
@@ -2132,12 +2319,11 @@ static void cleanup(int sig)
 template <>     bool   SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
 template <>     bool   SharedCache<arm>::addCacheSlideInfo()   { return true; }
 template <>     bool   SharedCache<x86>::addCacheSlideInfo()   { return false; }
-template <>     bool   SharedCache<ppc>::addCacheSlideInfo()   { return false; }
 
 
 
 template <typename A>
-bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
+bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
                                                                int archCount, bool keepSignatures)
 {
        bool didUpdate = false;
@@ -2243,7 +2429,7 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                        throwf("file modified during cache creation: %s", path);
 
                                if ( verbose )
-                                       fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getID().name);
+                                       fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getFilePath());
                                try {
                                        const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
                                        for (int i=0; i < segs.size(); ++i) {
@@ -2556,7 +2742,7 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
 
                                // write out cache file
                                if ( verbose )
-                                       fprintf(stderr, "update_dyld_shared_cache: writing cache to disk\n");
+                                       fprintf(stderr, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath);
                                if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
                                        throwf("write() failure creating cache file, errno=%d", errno);
                                if ( progress ) {
@@ -2594,6 +2780,8 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                }
                                
                                // move new cache file to correct location for use after reboot
+                               if ( verbose )
+                                       fprintf(stderr, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", fCacheFilePath);
                                result = ::rename(tempCachePath, fCacheFilePath);
                                if ( result != 0 ) 
                                        throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, fCacheFilePath, errno);
@@ -2661,6 +2849,11 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                                                fSizeOfFunctionStartsInCombinedLinkedit/1024,
                                                                fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit,
                                                                fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit+fSizeOfFunctionStartsInCombinedLinkedit);                              
+                                       if ( fSizeOfDataInCodeInCombinedLinkedit != 0 )
+                                               fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",          
+                                                               fSizeOfDataInCodeInCombinedLinkedit/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit+fSizeOfDataInCodeInCombinedLinkedit);                              
                                        if ( fSizeOfOldExternalRelocationsInCombinedLinkedit != 0 )
                                                fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",            
                                                                fSizeOfOldExternalRelocationsInCombinedLinkedit/1024,
@@ -2795,10 +2988,11 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
 
 
 
-static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
+static void setSharedDylibs(const char* rootPath, const char* overlayPath, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
 {
        // set file system root
-       ArchGraph::setFileSystemRoot(rootPath, usesOverlay);
+       ArchGraph::setFileSystemRoot(rootPath);
+       ArchGraph::setFileSystemOverlay(overlayPath);
 
        // initialize all architectures requested
        for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
@@ -2814,12 +3008,11 @@ static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::s
 }
 
 
-static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
+static void scanForSharedDylibs(const char* rootPath, const char* overlayPath, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
 {
        char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
-       // in -overlay mode, still look for roots in /var/db/dyld
        // in -root mode, look for roots in /rootpath/var/db/dyld
-       if ( !usesOverlay && (strlen(rootPath) != 0) ) {
+       if ( rootPath[0] != '\0' ) {
                strcpy(rootDirOfPathFiles, rootPath);
                strcat(rootDirOfPathFiles, dirOfPathFiles);
                dirOfPathFiles = rootDirOfPathFiles;
@@ -2860,14 +3053,14 @@ static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const ch
        
        if ( rootsPaths.size() == 0 )
                fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
-       setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
+       setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
 }
 
-static void setSharedDylibs(const char* rootPath, bool usesOverlay, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
+static void setSharedDylibs(const char* rootPath, const char* overlayPath, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
 {
        std::vector<const char*> rootsPaths;
        parsePathsFile(pathsFile, rootsPaths);
-       setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
+       setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
 }
 
 
@@ -2914,7 +3107,7 @@ static void deleteOrphanTempCacheFiles()
 
 
 
-static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const char* cacheDir, const std::set<ArchPair>& onlyArchs, 
+static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs, 
                                                                        bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures)
 {
        bool didUpdate = false;
@@ -2940,34 +3133,22 @@ static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const
                else
                        fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
                switch ( a->arch ) {
-                       case CPU_TYPE_POWERPC:
-                               {
-               #if __i386__ || __x86_64__
-                                       // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
-                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
-                                       didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
-               #else
-                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
-                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
-               #endif
-                               }
-                               break;
                        case CPU_TYPE_I386:
                                {
-                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
-                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_X86_64:
                                {
-                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
-                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_ARM:
                                {
-                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
-                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                }
@@ -2990,14 +3171,14 @@ int main(int argc, const char* argv[])
 {
        std::set<ArchPair> onlyArchs;
        const char* rootPath = "";
+       const char* overlayPath = "";
        const char* dylibListFile = NULL;
        bool force = false;
        bool alphaSort = false;
        bool optimize = true;
-       bool hasRoot = false;
-       bool hasOverlay = false;
        bool verify = false;
        bool keepSignatures = false;
+       bool explicitCacheDir = false;
        const char* cacheDir = NULL;
        
        try {
@@ -3035,31 +3216,24 @@ int main(int argc, const char* argv[])
                                                throw "-dylib_list missing path argument";
                                }
                                else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
-                                       if ( hasOverlay )
-                                               throw "cannot use both -root and -overlay";
                                        rootPath = argv[++i];
                                        if ( rootPath == NULL )
                                                throw "-root missing path argument";
-                                       hasRoot = true;
                                }
                                else if ( strcmp(arg, "-overlay") == 0 ) {
-                                       if ( hasRoot )
-                                               throw "cannot use both -root and -overlay";
-                                       rootPath = argv[++i];
-                                       if ( rootPath == NULL )
-                                               throw "-root missing path argument";
-                                       hasOverlay = true;
+                                       overlayPath = argv[++i];
+                                       if ( overlayPath == NULL )
+                                               throw "-overlay missing path argument";
                                }
                                else if ( strcmp(arg, "-cache_dir") == 0 ) {
                                        cacheDir = argv[++i];
                                        if ( cacheDir == NULL )
                                                throw "-cache_dir missing path argument";
+                                       explicitCacheDir = true;
                                }
                                else if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = argv[++i];
-                                       if ( strcmp(arch, "ppc") == 0 ) 
-                                               onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
-                                       else if ( strcmp(arch, "i386") == 0 )
+                                       if ( strcmp(arch, "i386") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
@@ -3071,13 +3245,14 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
                                        else if ( strcmp(arch, "armv7") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
+                                       else if ( strcmp(arch, "armv7f") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F));
+                                       else if ( strcmp(arch, "armv7k") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K));
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
                                else if ( strcmp(arg, "-universal_boot") == 0 ) {
-                       #if __ppc__
-                                       throwf("universal_boot option can only be used on Intel machines");
-                       #endif
                                        onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
                                        onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
                                }
@@ -3092,7 +3267,7 @@ int main(int argc, const char* argv[])
                        }
                }
                                
-               // strip tailing slashes on -root or -overlay
+               // strip tailing slashes on -root 
                // make it a real path so as to not make all dylibs look like symlink aliases
                if ( rootPath[0] != '\0' ) {
                        char realRootPath[MAXPATHLEN];
@@ -3101,16 +3276,18 @@ int main(int argc, const char* argv[])
                        rootPath = strdup(realRootPath);
                }
                
-               // set location to write cache dir
-               if ( cacheDir == NULL ) {
-                       if ( (rootPath[0] == '\0') || hasOverlay ) {
-                               cacheDir =  (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR);
-                       }
-                       else {
-                               asprintf((char**)&cacheDir, "%s/%s", rootPath, (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR));
-                       }
+               // strip tailing slashes on -overlay
+               if ( overlayPath[0] != '\0' ) {
+                       char realOverlayPath[MAXPATHLEN];
+                       if ( realpath(overlayPath, realOverlayPath) == NULL )
+                               throwf("realpath() failed on %s\n", overlayPath);
+                       overlayPath = strdup(realOverlayPath);
                }
 
+               // set default location to write cache dir
+               if ( cacheDir == NULL ) 
+                       cacheDir = (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR);
+
                // if no restrictions specified, use architectures that work on this machine
                if ( onlyArchs.size() == 0 ) {
                        if ( iPhoneOS ) {
@@ -3122,19 +3299,6 @@ int main(int argc, const char* argv[])
                                size_t len = sizeof(int);
                        #if __i386__ || __x86_64__
                                onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
-                               // check rosetta is installed
-                               char rosettaPath[1024];
-                               strlcpy(rosettaPath, rootPath, 1024);
-                               strlcat(rosettaPath, "/usr/libexec/oah/translate", 1024);
-                               struct stat stat_buf;
-                               if ( stat(rosettaPath, &stat_buf) == 0 ) {
-                                       onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
-                               }
-                               else if ( hasOverlay ) {
-                                       // in overlay mode, rosetta may be installed on base system, but is not in update root
-                                       if ( stat("/usr/libexec/oah/translate", &stat_buf) == 0 ) 
-                                               onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
-                               }
                                // check system is capable of running 64-bit programs
                                if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
                                        onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
@@ -3149,10 +3313,10 @@ int main(int argc, const char* argv[])
                
                // build list of shared dylibs
                if ( dylibListFile != NULL )
-                       setSharedDylibs(rootPath, hasOverlay, dylibListFile, onlyArchs);
+                       setSharedDylibs(rootPath, overlayPath, dylibListFile, onlyArchs);
                else
-                       scanForSharedDylibs(rootPath, hasOverlay, "/var/db/dyld/shared_region_roots/", onlyArchs);
-               updateSharedeCacheFile(rootPath, hasOverlay, cacheDir, onlyArchs, force, alphaSort, optimize, 
+                       scanForSharedDylibs(rootPath, overlayPath, "/var/db/dyld/shared_region_roots/", onlyArchs);
+               updateSharedeCacheFile(rootPath, overlayPath, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize, 
                                                                false, verify, keepSignatures);
        }
        catch (const char* msg) {
index 3b0e8242155f1c6829f64b00821761a329866ddc..58b22829d8b5bb5fe507f715e2d2f96964f7373a 100644 (file)
@@ -64,7 +64,7 @@ uintptr_t                                                             ImageLoader::fgNextPIEDylibAddress = 0;
 
 
 ImageLoader::ImageLoader(const char* path, unsigned int libCount)
-       : fPath(path), fDevice(0), fInode(0), fLastModified(0), 
+       : fPath(path), fRealPath(NULL), fDevice(0), fInode(0), fLastModified(0), 
        fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
        fDynamicReferenceCount(0), fDynamicReferences(NULL), fInitializerRecursiveLock(NULL), 
        fDepth(0), fLoadOrder(fgLoadOrdinal++), fState(0), fLibraryCount(libCount), 
@@ -72,7 +72,8 @@ ImageLoader::ImageLoader(const char* path, unsigned int libCount)
        fHideSymbols(false), fMatchByInstallName(false),
        fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false), 
     fBeingRemoved(false), fAddFuncNotified(false),
-       fPathOwnedByImage(false), fWeakSymbolsBound(false)
+       fPathOwnedByImage(false), fIsReferencedDownward(false), 
+       fIsReferencedUpward(false), fWeakSymbolsBound(false)
 {
        if ( fPath != NULL )
                fPathHash = hash(fPath);
@@ -96,6 +97,8 @@ void ImageLoader::deleteImage(ImageLoader* image)
 
 ImageLoader::~ImageLoader()
 {
+       if ( fRealPath != NULL ) 
+               delete [] fRealPath;
        if ( fPathOwnedByImage && (fPath != NULL) ) 
                delete [] fPath;
        if ( fDynamicReferences != NULL ) {
@@ -166,6 +169,7 @@ void ImageLoader::setPath(const char* path)
        strcpy((char*)fPath, path);
        fPathOwnedByImage = true;  // delete fPath when this image is destructed
        fPathHash = hash(fPath);
+       fRealPath = NULL;
 }
 
 void ImageLoader::setPathUnowned(const char* path)
@@ -178,6 +182,21 @@ void ImageLoader::setPathUnowned(const char* path)
        fPathHash = hash(fPath);
 }
 
+void ImageLoader::setPaths(const char* path, const char* realPath)
+{
+       this->setPath(path);
+       fRealPath = new char[strlen(realPath)+1];
+       strcpy((char*)fRealPath, realPath);
+}
+
+const char* ImageLoader::getRealPath() const 
+{ 
+       if ( fRealPath != NULL ) 
+               return fRealPath;
+       else
+               return fPath; 
+}
+
 
 uint32_t ImageLoader::hash(const char* path)
 {
@@ -243,8 +262,6 @@ time_t ImageLoader::lastModified() const
 
 bool ImageLoader::containsAddress(const void* addr) const
 {
-       if ( ! this->isLinked() )
-               return false;
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                const uint8_t* start = (const uint8_t*)segActualLoadAddress(i);
                const uint8_t* end = (const uint8_t*)segActualEndAddress(i);
@@ -301,7 +318,6 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcep
                        const ImageLoader** dsiStart, const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const
 {
        const ImageLoader::Symbol* sym;
-       
        // search self
        if ( notInImgageList(this, dsiStart, dsiCur) ) {
                sym = this->findExportedSymbol(name, false, foundIn);
@@ -481,7 +497,7 @@ unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
                unsigned int minDependentDepth = maxDepth;
                for(unsigned int i=0; i < libraryCount(); ++i) {
                        ImageLoader* dependentImage = libImage(i);
-                       if ( dependentImage != NULL ) {
+                       if ( (dependentImage != NULL) && !libIsUpward(i) ) {
                                unsigned int d = dependentImage->recursiveUpdateDepth(maxDepth);
                                if ( d < minDependentDepth )
                                        minDependentDepth = d;
@@ -538,8 +554,13 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                }
                                if ( fNeverUnload )
                                        dependentLib->setNeverUnload();
-                               if ( ! requiredLibInfo.upward )
+                               if ( requiredLibInfo.upward ) {
+                                       dependentLib->fIsReferencedUpward = true;
+                               }
+                               else { 
                                        dependentLib->fStaticReferenceCount += 1;
+                                       dependentLib->fIsReferencedDownward = true;
+                               }
                                LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
                                depLibReRequired = requiredLibInfo.required;
                                depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
@@ -549,7 +570,8 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                        depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib);
                                }
                                // check found library version is compatible
-                               if ( actualInfo.minVersion < requiredLibInfo.info.minVersion ) {
+                               // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version
+                               if ( (requiredLibInfo.info.minVersion != 0xFFFFFFFF) && (actualInfo.minVersion < requiredLibInfo.info.minVersion) ) {
                                        // record values for possible use by CrashReporter or Finder
                                        dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
                                                        this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
@@ -582,7 +604,7 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                                (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL);
                                        else
                                                (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL);
-                                       dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getPath(), msg);
+                                       dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getRealPath(), msg);
                                }
                                // ok if weak library not found
                                dependentLib = NULL;
@@ -872,20 +894,25 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                // break cycles
                fState = dyld_image_state_dependents_initialized-1;
                try {
+                       bool hasUpwards = false;
                        // initialize lower level libraries first
                        for(unsigned int i=0; i < libraryCount(); ++i) {
                                ImageLoader* dependentImage = libImage(i);
-                               if ( dependentImage != NULL )
-                               // don't try to initialize stuff "above" me
-                               if ( (dependentImage != NULL) && (dependentImage->fDepth >= fDepth) && !libIsUpward(i) )
-                                       dependentImage->recursiveInitialization(context, this_thread, timingInfo);
+                               if ( dependentImage != NULL ) {
+                                       // don't try to initialize stuff "above" me
+                                       bool isUpward = libIsUpward(i);
+                                       if ( (dependentImage->fDepth >= fDepth) && !isUpward ) {
+                                               dependentImage->recursiveInitialization(context, this_thread, timingInfo);
+                                       }
+                                       hasUpwards |= isUpward;
+                }
                        }
                        
                        // record termination order
                        if ( this->needsTermination() )
                                context.terminationRecorder(this);
                        
-                       // let objc know we are about to initalize this image
+                       // let objc know we are about to initialize this image
                        uint64_t t1 = mach_absolute_time();
                        fState = dyld_image_state_dependents_initialized;
                        oldState = fState;
@@ -894,7 +921,19 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                        // initialize this image
                        bool hasInitializers = this->doInitialization(context);
                        
-                       // let anyone know we finished initalizing this image
+                       // <rdar://problem/10491874> initialize any upward depedencies
+                       if ( hasUpwards ) {
+                               for(unsigned int i=0; i < libraryCount(); ++i) {
+                                       ImageLoader* dependentImage = libImage(i);
+                                       // <rdar://problem/10643239> ObjC CG hang
+                                       // only init upward lib here if lib is not downwardly referenced somewhere 
+                                       if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) {
+                                               dependentImage->recursiveInitialization(context, this_thread, timingInfo);
+                                       }
+                               }
+                       }
+            
+                       // let anyone know we finished initializing this image
                        fState = dyld_image_state_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_initialized, this);
index 582e60c0e1961f805130dd6e0a753e84caffc623..83bc1fe03788655a1926e970c1025db4727edb83 100644 (file)
 #elif __x86_64__
        #define SHARED_REGION_BASE SHARED_REGION_BASE_X86_64
        #define SHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64
-#elif __ppc__
-       #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC
-       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC
-#elif __ppc64__
-       #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC64
-       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC64
 #elif __arm__
        #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM
        #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
        #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
 #endif
 
+#ifndef LC_MAIN
+       #define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */
+       struct entry_point_command {
+               uint32_t  cmd;  /* LC_MAIN only used in MH_EXECUTE filetypes */
+               uint32_t  cmdsize;      /* 24 */
+               uint64_t  entryoff;     /* file (__TEXT) offset of main() */
+               uint64_t  stacksize;/* if not zero, initial stack size */
+       };
+#endif
 
 #define SPLIT_SEG_SHARED_REGION_SUPPORT __arm__
-#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define PREBOUND_IMAGE_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__ || __arm__)
-#define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
+#define SPLIT_SEG_DYLIB_SUPPORT (__i386__ || __arm__)
+#define PREBOUND_IMAGE_SUPPORT (__i386__ || __arm__)
+#define TEXT_RELOC_SUPPORT (__i386__ || __arm__)
+#define DYLD_SHARED_CACHE_SUPPORT (__i386__ ||  __x86_64__ || __arm__)
+#define SUPPORT_OLD_CRT_INITIALIZATION (__i386__)
 #define SUPPORT_LC_DYLD_ENVIRONMENT  (__i386__ || __x86_64__)
 #define SUPPORT_VERSIONED_PATHS  (__i386__ || __x86_64__)
 #if __IPHONE_OS_VERSION_MIN_REQUIRED
@@ -89,7 +92,7 @@
        #define CORESYMBOLICATION_SUPPORT   (__i386__ || __x86_64__)
 #endif
 #if __arm__
-       #define INITIAL_IMAGE_COUNT 100
+       #define INITIAL_IMAGE_COUNT 256
 #else
        #define INITIAL_IMAGE_COUNT 200
 #endif
@@ -187,6 +190,7 @@ public:
                void                    (*removeImage)(ImageLoader* image);
                void                    (*registerDOFs)(const std::vector<DOFInfo>& dofs);
                void                    (*clearAllDepths)();
+               void                    (*printAllDepths)();
                unsigned int    (*imageCount)();
                void                    (*setNewProgramVars)(const ProgramVars&);
                bool                    (*inSharedCache)(const char* path);
@@ -285,6 +289,9 @@ public:
 
        uint32_t                                                        getPathHash() const { return fPathHash; }
 
+                                                                               // get the "real" path for this image (e.g. no @rpath)
+       const char*                                                     getRealPath() const;
+
                                                                                // get path this image is intended to be placed on disk or NULL if no preferred install location
        virtual const char*                                     getInstallPath() const = 0;
 
@@ -325,7 +332,10 @@ public:
                                                                                // st_mtime from stat() on file
        time_t                                                          lastModified() const;
 
-                                                                               // only valid for main executables, returns a pointer its entry point
+                                                                               // only valid for main executables, returns a pointer its entry point from LC_UNIXTHREAD
+       virtual void*                                           getThreadPC() const = 0;
+       
+                                                                               // only valid for main executables, returns a pointer its main from LC_<MAIN
        virtual void*                                           getMain() const = 0;
        
                                                                                // dyld API's require each image to have an associated mach_header
@@ -478,7 +488,11 @@ public:
        bool                                                            neverUnload() const { return fNeverUnload; }
 
        void                                                            setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
+       
+       bool                                                            isReferencedDownward() { return fIsReferencedDownward; }
 
+       bool                                                            isReferencedUpward() { return fIsReferencedUpward; }
+       
                                                                                // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
        static void                                                     printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo);
                                
@@ -490,10 +504,12 @@ public:
                                                                                // used instead of directly deleting image
        static void                                                     deleteImage(ImageLoader*);
                
-                       void                                            setPath(const char* path);      // only called for images created from memory
+                       void                                            setPath(const char* path);
+                       void                                            setPaths(const char* path, const char* realPath);
                        void                                            setPathUnowned(const char* path);
                                                
                        void                                            clearDepth() { fDepth = 0; }
+                       int                                                     getDepth() { return fDepth; }
                        
                        void                                            setBeingRemoved() { fBeingRemoved = true; }
                        bool                                            isBeingRemoved() const { return fBeingRemoved; }
@@ -638,6 +654,7 @@ protected:
        static uint64_t                         fgTotalInitTime;
        static std::vector<InterposeTuple>      fgInterposingTuples;
        const char*                                     fPath;
+       const char*                                     fRealPath;
        dev_t                                           fDevice;
        ino_t                                           fInode;
        time_t                                          fLastModified;
@@ -677,6 +694,8 @@ private:
                                                                fBeingRemoved : 1,
                                                                fAddFuncNotified : 1,
                                                                fPathOwnedByImage : 1,
+                                                               fIsReferencedDownward : 1,
+                                                               fIsReferencedUpward : 1,
                                                                fWeakSymbolsBound : 1;
 
        static uint16_t                         fgLoadOrdinal;
index b068b7a03779efb0bfba4f7c656c5076d002f071..3a8ad7d17e2096b3266d9ee15df7223e026c2c8c 100644 (file)
@@ -88,7 +88,7 @@ ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, uns
        fReadOnlyImportSegment(false),
 #endif
        fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
-       fHasInitializers(false), fHasTerminators(false), fGoodFirstSegment(false), fRegisteredAsRequiresCoalescing(false)
+       fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false)
 {
        fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);        
 
@@ -121,10 +121,14 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
        *segCount = 0;
        *libCount = 0;
        *codeSigCmd = NULL;
+       struct macho_segment_command* segCmd;
+#if CODESIGNING_SUPPORT
+       bool foundLoadCommandSegment = false;
+#endif
        const uint32_t cmd_count = mh->ncmds;
-       const struct load_command* const cmds    = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
+       const struct load_command* const startCmds    = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
        const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds);
-       const struct load_command* cmd = cmds;
+       const struct load_command* cmd = startCmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_DYLD_INFO:
@@ -132,9 +136,20 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                                *compressed = true;
                                break;
                        case LC_SEGMENT_COMMAND:
+                               segCmd = (struct macho_segment_command*)cmd;
                                // ignore zero-sized segments
-                               if ( ((struct macho_segment_command*)cmd)->vmsize != 0 )
+                               if ( segCmd->vmsize != 0 )
                                        *segCount += 1;
+#if CODESIGNING_SUPPORT
+                               // <rdar://problem/7942521> all load commands must be in an executable segment
+                               if ( (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) {
+                                       if ( (segCmd->fileoff != 0) || (segCmd->filesize < (mh->sizeofcmds+sizeof(macho_header))) ) 
+                                               dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname); 
+                                       if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) ) 
+                                               dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname); 
+                                       foundLoadCommandSegment = true;
+                               }
+#endif         
                                break;
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
@@ -148,11 +163,17 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                }
                uint32_t cmdLength = cmd->cmdsize;
                cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
-               if ( cmd > endCmds ) {
+               if ( (cmd > endCmds) || (cmd < startCmds) ) {
                        dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 
                                                        i, cmdLength, mh->sizeofcmds, path);
                }
        }
+       
+#if CODESIGNING_SUPPORT
+       if ( ! foundLoadCommandSegment )
+               throw "load commands not in a segment";
+#endif
+               
        // fSegmentsArrayCount is only 8-bits
        if ( *segCount > 255 )
                dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
@@ -287,6 +308,8 @@ void ImageLoaderMachO::parseLoadCmds()
        const dyld_info_command* dyldInfo = NULL;
        const macho_nlist* symbolTable = NULL;
        const char* symbolTableStrings = NULL;
+       const struct load_command* firstUnknownCmd = NULL;
+       const struct version_min_command* minOSVersionCmd = NULL;
        const dysymtab_command* dynSymbolTable = NULL;
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
@@ -352,14 +375,34 @@ void ImageLoaderMachO::parseLoadCmds()
                        case LC_LOAD_WEAK_DYLIB:
                    case LC_REEXPORT_DYLIB:
                        case LC_LOAD_UPWARD_DYLIB:
+                       case LC_MAIN:
                                // do nothing, just prevent LC_REQ_DYLD exception from occuring
                                break;
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                               minOSVersionCmd = (version_min_command*)cmd;
+                               break;
                        default:
-                               if ( (cmd->cmd & LC_REQ_DYLD) != 0 )
-                                       dyld::throwf("unknown required load command 0x%08X", cmd->cmd);
+                               if ( (cmd->cmd & LC_REQ_DYLD) != 0 ) {
+                                       if ( firstUnknownCmd == NULL )
+                                               firstUnknownCmd = cmd;
+                               }
+                               break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
+       if ( firstUnknownCmd != NULL ) {
+               if ( minOSVersionCmd != NULL )  {
+                       dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)", 
+                                                this->getShortName(),
+                                                minOSVersionCmd->version >> 16, ((minOSVersionCmd->version >> 8) & 0xff), 
+                                                firstUnknownCmd->cmd);
+               }
+               else {
+                       dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd->cmd);
+               }
+       }
+       
        
        if ( dyldInfo != NULL )
                this->setDyldInfo(dyldInfo);
@@ -673,11 +716,6 @@ const char* ImageLoaderMachO::getInstallPath() const
 void ImageLoaderMachO::registerInterposing()
 {
        // mach-o files advertise interposing by having a __DATA __interpose section
-       uintptr_t textStart = this->segActualLoadAddress(0);
-       uintptr_t textEnd = this->segActualEndAddress(0);
-       // <rdar://problem/8268602> verify that the first segment load command is for a read-only segment
-       if ( ! fGoodFirstSegment )
-               return;
        struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
@@ -699,7 +737,7 @@ void ImageLoaderMachO::registerInterposing()
                                                                tuple.replacementImage  = this;
                                                                tuple.replacee                  = interposeArray[i].replacee;
                                                                // <rdar://problem/7937695> verify that replacement is in this image
-                                                               if ( (tuple.replacement >= textStart) && (tuple.replacement < textEnd) ) {
+                                                               if ( this->containsAddress((void*)tuple.replacement) ) {
                                                                        for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
                                                                                if ( it->replacee == tuple.replacee ) {
                                                                                        tuple.replacee = it->replacement;
@@ -717,6 +755,26 @@ void ImageLoaderMachO::registerInterposing()
        }
 }
 
+void* ImageLoaderMachO::getThreadPC() const
+{
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_MAIN ) {
+                       entry_point_command* mainCmd = (entry_point_command*)cmd;
+                       void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData);
+                       // <rdar://problem/8543820&9228031> verify entry point is in image
+                       if ( this->containsAddress(entry) )
+                               return entry;
+                       else
+                               throw "LC_MAIN entryoff is out of range";
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       return NULL;
+}
+
 
 void* ImageLoaderMachO::getMain() const
 {
@@ -727,30 +785,28 @@ void* ImageLoaderMachO::getMain() const
                switch (cmd->cmd) {
                        case LC_UNIXTHREAD:
                        {
-                       #if __ppc__
-                               const ppc_thread_state_t* registers = (ppc_thread_state_t*)(((char*)cmd) + 16);
-                               return (void*)(registers->srr0 + fSlide);
-                       #elif __ppc64__
-                               const ppc_thread_state64_t* registers = (ppc_thread_state64_t*)(((char*)cmd) + 16);
-                               return (void*)(registers->srr0 + fSlide);
-                       #elif __i386__
+                       #if __i386__
                                const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
-                               return (void*)(registers->eip + fSlide);
+                               void* entry = (void*)(registers->eip + fSlide);
                        #elif __x86_64__
                                const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
-                               return (void*)(registers->rip + fSlide);
+                               void* entry = (void*)(registers->rip + fSlide);
                        #elif __arm__
                                const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16);
-                               return (void*)(registers->__pc + fSlide);
+                               void* entry = (void*)(registers->__pc + fSlide);
                        #else
                                #warning need processor specific code
                        #endif
+                               // <rdar://problem/8543820&9228031> verify entry point is in image
+                               if ( this->containsAddress(entry) ) {
+                                       return entry;
+                               }
                        }
                        break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       return NULL;
+       throw "no valid entry point";
 }
 
 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
@@ -1306,9 +1362,7 @@ uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t l
 
 #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__
+#if __i386__
        static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
 #endif
 #endif
@@ -1331,11 +1385,10 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
        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 ) {
+       // There used to be some optimizations to skip this section scan, but we need to handle the 
+       // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
+       // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
+       if ( true ) {
                cmd = cmds;
                for (uint32_t i = 0; i < cmd_count; ++i) {
                        if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
@@ -1377,6 +1430,16 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
                                #endif
                                                                }
                                                        }
+                                                       else if ( mh->filetype == MH_DYLIB ) {
+                                                               const char* installPath = this->getInstallPath();
+                                                               if ( (installPath != NULL) && (strncmp(installPath, "/usr/lib/", 9) == 0) ) {
+                                                                       if ( sect->size > offsetof(DATAdyld, vars) ) {
+                                                                               // use ProgramVars from libdyld.dylib but tweak mh field to correct value
+                                                                               dd->vars.mh = context.mainExecutable->machHeader();
+                                                                               context.setNewProgramVars(dd->vars);
+                                                                       }
+                                                               }
+                                                       }
                                                }
                                                else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) {
                                                        // this is a Mac OS X 10.6 or later main executable 
@@ -1451,16 +1514,6 @@ bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
 void ImageLoaderMachO::doImageInit(const LinkContext& context)
 {
        if ( fHasDashInit ) {
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
-               // <rdar://problem/8543820> verify initializers are in first segment for dylibs
-               if ( this->isDylib() && !fGoodFirstSegment ) {
-                       if ( context.verboseInit )
-                               dyld::log("dyld: ignoring -init in %s\n", this->getPath());
-                       return;
-               }
-               uintptr_t textStart = this->segActualLoadAddress(0);
-               uintptr_t textEnd = this->segActualEndAddress(0);
-#endif
                const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
                const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
                const struct load_command* cmd = cmds;
@@ -1468,20 +1521,13 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
                        switch (cmd->cmd) {
                                case LC_ROUTINES_COMMAND:
                                        Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
-                                       // <rdar://problem/8543820> verify initializers are in first segment for dylibs
-                                       if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
-                                               if ( context.verboseInit )
-                                                       dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
-                                       }
-                                       else {
-#endif
-                                               if ( context.verboseInit )
-                                                       dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
-                                               func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                                       // <rdar://problem/8543820&9228031> verify initializers are in image
+                                       if ( ! this->containsAddress((void*)func) ) {
+                                               dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
                                        }
-#endif
+                                       if ( context.verboseInit )
+                                               dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
+                                       func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
                                        break;
                        }
                        cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
@@ -1492,16 +1538,6 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
 {
        if ( fHasInitializers ) {
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
-               // <rdar://problem/8543820> verify initializers are in first segment for dylibs
-               if ( this->isDylib() && !fGoodFirstSegment ) {
-                       if ( context.verboseInit )
-                               dyld::log("dyld: ignoring all initializers in %s\n", this->getPath());
-                       return;
-               }
-               uintptr_t textStart = this->segActualLoadAddress(0);
-               uintptr_t textEnd = this->segActualEndAddress(0);
-#endif
                const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
                const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
                const struct load_command* cmd = cmds;
@@ -1517,20 +1553,13 @@ void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
                                                const uint32_t count = sect->size / sizeof(uintptr_t);
                                                for (uint32_t i=0; i < count; ++i) {
                                                        Initializer func = inits[i];
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
-                                                       // <rdar://problem/8543820> verify initializers are in first segment for dylibs
-                                                       if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
-                                                               if ( context.verboseInit )
-                                                                       dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
+                                                       // <rdar://problem/8543820&9228031> verify initializers are in image
+                                                       if ( ! this->containsAddress((void*)func) ) {
+                                                               dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
                                                        }
-                                                       else {
-#endif                                         
-                                                               if ( context.verboseInit )
-                                                                       dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
-                                                               func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
-                                                       }
-#endif
+                                                       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);
                                                }
                                        }
                                }
@@ -1620,6 +1649,10 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
                                                const uint32_t count = sect->size / sizeof(uintptr_t);
                                                for (uint32_t i=count; i > 0; --i) {
                                                        Terminator func = terms[i-1];
+                                                       // <rdar://problem/8543820&9228031> verify terminators are in image
+                                                       if ( ! this->containsAddress((void*)func) ) {
+                                                               dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath());
+                                                       }
                                                        if ( context.verboseInit )
                                                                dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
                                                        func();
@@ -1726,24 +1759,11 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
        intptr_t slide = this->assignSegmentAddresses(context);
        if ( context.verboseMapping )
                dyld::log("dyld: Mapping %s\n", this->getPath());
-       // <rdar://problem/8268602> verify that the first segment load command is for a r-x segment
-       // that starts at begining of file and is larger than all load commands
-       uintptr_t firstSegMappedStart = segPreferredLoadAddress(0) + slide;
-       uintptr_t firstSegMappedEnd = firstSegMappedStart + this->segSize(0);
-       if ( (this->segLoadCommand(0)->initprot == (VM_PROT_EXECUTE|VM_PROT_READ)) 
-               && (this->segFileOffset(0) == 0) 
-               && (this->segFileSize(0) != 0) 
-               && (this->segSize(0) > ((macho_header*)fMachOData)->sizeofcmds) ) {
-                       fGoodFirstSegment = true;
-       }
        // map in all segments
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
                vm_size_t size = segFileSize(i);
                uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
-               // <rdar://problem/8268602> verify other segments map after first
-               if ( (i != 0) && (requestedLoadAddress < firstSegMappedEnd) )
-                       fGoodFirstSegment = false;
                int protection = 0;
                if ( !segUnaccessible(i) ) {
                        // If has text-relocs, don't set x-bit initially.
index a2b657a9c554aa9b426daf5202cf732030f9f7c2..c3e192bb7ff06b531dfe72c7522c2d906029d56c 100644 (file)
@@ -50,6 +50,7 @@ public:
        bool                                                            inSharedCache() const { return fInSharedCache; }
        const char*                                                     getInstallPath() const;
        virtual void*                                           getMain() const;
+       virtual void*                                           getThreadPC() const;
        virtual const struct mach_header*   machHeader() const;
        virtual uintptr_t                                       getSlide() const;
        virtual const void*                                     getEnd() const;
@@ -218,7 +219,6 @@ protected:
                                                                                        fHasDashInit : 1,
                                                                                        fHasInitializers : 1,
                                                                                        fHasTerminators : 1,
-                                                                                       fGoodFirstSegment : 1,
                                                                                        fRegisteredAsRequiresCoalescing : 1;    // <rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
                                                                                        
                                                                                        
index 33b055d94bee273ef19a8d5c9a851f3de26d7171..2d0cf1b20904aaafb4247bccd55bc28779529d36 100644 (file)
@@ -44,9 +44,6 @@
 #include <libkern/OSAtomic.h>
 #include <libkern/OSCacheControl.h>
 
-#if __ppc__ || __ppc64__
-       #include <mach-o/ppc/reloc.h>
-#endif
 #if __x86_64__
        #include <mach-o/x86_64/reloc.h>
 #endif
 #include "ImageLoaderMachOClassic.h"
 #include "mach-o/dyld_images.h"
 
-// optimize strcmp for ppc
-#if __ppc__
-       #include <ppc_intrinsics.h>
-#else
-       #define astrcmp(a,b) strcmp(a,b)
-#endif
-
-
 // in dyldStartup.s
 extern "C" void fast_stub_binding_helper_interface();
 
@@ -163,11 +152,12 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char
                const char* installName = image->getInstallPath();
                if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
                        image->setPathUnowned(installName);
-               else if ( path[0] != '/' ) {
+               else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
+                       // rdar://problem/10733082 Fix up @path based paths during introspection
                        // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
                        char realPath[MAXPATHLEN];
-                       if ( realpath(path, realPath) != NULL )
-                               image->setPath(realPath);
+                       if ( fcntl(fd, F_GETPATH, realPath) == 0 ) 
+                               image->setPaths(path, realPath);
                        else
                                image->setPath(path);
                }
@@ -729,33 +719,6 @@ uintptr_t ImageLoaderMachOClassic::getRelocBase()
 }
 
 
-#if __ppc__
-static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationType, uint16_t otherHalf, uintptr_t slide)
-{
-       // low 16 bits of 32-bit ppc instructions need fixing
-       struct ppcInstruction { uint16_t opcode; int16_t immediateValue; };
-       ppcInstruction* instruction = (ppcInstruction*)locationToFix;
-       //uint32_t before = *((uint32_t*)locationToFix);
-       switch ( relocationType )
-       {
-               case PPC_RELOC_LO16: 
-                       instruction->immediateValue = ((otherHalf << 16) | instruction->immediateValue) + slide;
-                       break;
-               case PPC_RELOC_HI16: 
-                       instruction->immediateValue = ((((instruction->immediateValue << 16) | otherHalf) + slide) >> 16);
-                       break;
-               case PPC_RELOC_HA16: 
-                       int16_t signedOtherHalf = (int16_t)(otherHalf & 0xffff);
-                       uint32_t temp = (instruction->immediateValue << 16) + signedOtherHalf + slide;
-                       if ( (temp & 0x00008000) != 0 )
-                               temp += 0x00008000;
-                       instruction->immediateValue = temp >> 16;
-       }
-       //uint32_t after = *((uint32_t*)locationToFix);
-       //dyld::log("dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
-}
-#endif
-
 #if PREBOUND_IMAGE_SUPPORT
 void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context)
 {
@@ -770,11 +733,6 @@ void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& conte
                        if (sreloc->r_length == RELOC_SIZE) {
                                uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
                                switch(sreloc->r_type) {
-               #if __ppc__ 
-                                       case PPC_RELOC_PB_LA_PTR:
-                                               *locationToFix = sreloc->r_value + slide;
-                                               break;
-               #endif
                #if __i386__
                                        case GENERIC_RELOC_PB_LA_PTR:
                                                *locationToFix = sreloc->r_value + slide;
@@ -809,6 +767,7 @@ void ImageLoaderMachOClassic::rebase(const LinkContext& context)
        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) {
+               uintptr_t rebaseAddr;
                try {
        #if LINKEDIT_USAGE_DEBUG
                        noteAccessedLinkEditAddress(reloc);
@@ -823,7 +782,12 @@ void ImageLoaderMachOClassic::rebase(const LinkContext& context)
                                throw "bad local relocation pc_rel";
                        if ( reloc->r_extern != 0 ) 
                                throw "extern relocation found with local relocations";
-                       *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
+                       rebaseAddr = reloc->r_address + relocBase;
+                       if ( ! this->containsAddress((void*)rebaseAddr) )
+                               dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
+                       *((uintptr_t*)rebaseAddr) += slide;
+                       if ( context.verboseRebase )
+                               dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
                #else   
                        if ( (reloc->r_address & R_SCATTERED) == 0 ) {
                                if ( reloc->r_symbolnum == R_ABS ) {
@@ -832,17 +796,13 @@ void ImageLoaderMachOClassic::rebase(const LinkContext& context)
                                else if (reloc->r_length == RELOC_SIZE) {
                                        switch(reloc->r_type) {
                                                case GENERIC_RELOC_VANILLA:
-                                                       *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
+                                                       rebaseAddr = reloc->r_address + relocBase;
+                                                       if ( ! this->containsAddress((void*)rebaseAddr) )
+                                                               dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
+                                                       *((uintptr_t*)rebaseAddr) += slide;
+                                                       if ( context.verboseRebase )
+                                                               dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
                                                        break;
-                       #if __ppc__
-                                               case PPC_RELOC_HI16: 
-                                               case PPC_RELOC_LO16: 
-                                               case PPC_RELOC_HA16: 
-                                                       // some tools leave object file relocations in linked images
-                                                       otherRelocsPPC((uintptr_t*)(reloc->r_address + relocBase), reloc->r_type, reloc[1].r_address, slide);
-                                                       ++reloc; // these relocations come in pairs, skip next
-                                                       break;
-                       #endif
                                                default:
                                                        throw "unknown local relocation type";
                                        }
@@ -857,26 +817,13 @@ void ImageLoaderMachOClassic::rebase(const LinkContext& context)
                                        uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
                                        switch(sreloc->r_type) {
                                                case GENERIC_RELOC_VANILLA:
+                                                       if ( ! this->containsAddress((void*)locationToFix) ) 
+                                                               dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix);
                                                        *locationToFix += slide;
+                                                       if ( context.verboseRebase )
+                                                               dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix, slide);
                                                        break;
-                       #if __ppc__
-                                               case PPC_RELOC_HI16: 
-                                               case PPC_RELOC_LO16: 
-                                               case PPC_RELOC_HA16: 
-                                                       // Metrowerks compiler sometimes leaves object file relocations in linked images???
-                                                       ++reloc; // these relocations come in pairs, get next one
-                                                       otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide);
-                                                       break;
-                                               case PPC_RELOC_PB_LA_PTR:
-                                                       // do nothing
-                                                       break;
-                       #elif __ppc64__
-                                               case PPC_RELOC_PB_LA_PTR:
-                                                       // needed for compatibility with ppc64 binaries built with the first ld64
-                                                       // which used PPC_RELOC_PB_LA_PTR relocs instead of GENERIC_RELOC_VANILLA for lazy pointers
-                                                       *locationToFix += slide;
-                                                       break;
-                       #elif __i386__
+                       #if __i386__
                                                case GENERIC_RELOC_PB_LA_PTR:
                                                        // do nothing
                                                        break;
@@ -932,7 +879,7 @@ const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const cha
                noteAccessedLinkEditAddress(pivot);
                noteAccessedLinkEditAddress(pivotStr);
 #endif
-               int cmp = astrcmp(key, pivotStr);
+               int cmp = strcmp(key, pivotStr);
                if ( cmp == 0 )
                        return pivot;
                if ( cmp > 0 ) {
@@ -964,7 +911,7 @@ const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key,
                noteAccessedLinkEditAddress(pivot);
                noteAccessedLinkEditAddress(pivotStr);
 #endif
-               int cmp = astrcmp(key, pivotStr);
+               int cmp = strcmp(key, pivotStr);
                if ( cmp == 0 )
                        return pivot;
                if ( cmp > 0 ) {
@@ -1266,6 +1213,8 @@ void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& conte
                                        {
                                                const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
                                                uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
+                                               if ( ! this->containsAddress((void*)location) )
+                                                       dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location, this->getPath());
                                                uintptr_t value = *location;
                                                bool symbolAddrCached = true;
                                        #if __i386__
index dda3e8af74dfc2c370bea6c486f717287066d5c8..2d0cca2446e7b5c99aa47090af30f3a03a50d380 100644 (file)
@@ -87,7 +87,7 @@ static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end)
                if (p == end)
                        throw "malformed sleb128";
                byte = *p++;
-               result |= ((byte & 0x7f) << bit);
+               result |= (((int64_t)(byte & 0x7f)) << bit);
                bit += 7;
        } while (byte & 0x80);
        // sign extend negative numbers
@@ -161,11 +161,12 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                else if ( (installName != NULL) && (strcmp(path, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName, "/usr/lib/libSystem.B.dylib") == 0) )
                        image->setPathUnowned("/usr/lib/libSystem.B.dylib");
 #endif
-               else if ( path[0] != '/' ) {
+               else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
+                       // rdar://problem/10733082 Fix up @rpath based paths during introspection
                        // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
                        char realPath[MAXPATHLEN];
-                       if ( realpath(path, realPath) != NULL )
-                               image->setPath(realPath);
+                       if ( fcntl(fd, F_GETPATH, realPath) == 0 ) 
+                               image->setPaths(path, realPath);
                        else
                                image->setPath(path);
                }
@@ -204,7 +205,6 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(con
 
                // remember this is from shared cache and cannot be unloaded
                image->fInSharedCache = true;
-               image->fGoodFirstSegment = true;
                image->setNeverUnload();
                image->setSlide(slide);
 
@@ -393,6 +393,9 @@ void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int ad
 
 void ImageLoaderMachOCompressed::rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type)
 {
+       if ( context.verboseRebase ) {
+               dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)addr, slide);
+       }
        //dyld::log("0x%08lX type=%d\n", addr, type);
        uintptr_t* locationToFix = (uintptr_t*)addr;
        switch (type) {
@@ -637,7 +640,18 @@ uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& c
        if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR ) {
                if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
                        // this node has a stub and resolver, run the resolver to get target address
-                       read_uleb128(exportNode, exportTrieEnd); // skip over stub
+                       uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData; // skip over stub
+                       // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
+                       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                               // replace all references to 'replacee' with 'replacement'
+                               if ( stub == it->replacee ) {
+                                       if ( context.verboseInterposing ) {
+                                               dyld::log("dyld interposing: lazy replace 0x%lX with 0x%lX from %s\n", 
+                                                                 it->replacee, it->replacement, this->getPath());
+                                       }
+                                       return it->replacement;
+                               }
+                       }
                        typedef uintptr_t (*ResolverProc)(void);
                        ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
                        uintptr_t result = (*resolver)();
index 31265a9b7bad6c984fd1d600658aeec4b90a78e4..6854ef51f92ec64e809ef04a361c0112b0672774 100644 (file)
 #ifndef CPU_SUBTYPE_ARM_V7
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
+#ifndef CPU_SUBTYPE_ARM_V7F
+       #define CPU_SUBTYPE_ARM_V7F                     ((cpu_subtype_t) 10)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+       #define CPU_SUBTYPE_ARM_V7S                     ((cpu_subtype_t) 11)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+       #define CPU_SUBTYPE_ARM_V7K                     ((cpu_subtype_t) 12)
+#endif
 #ifndef LC_DYLD_ENVIRONMENT
        #define LC_DYLD_ENVIRONMENT                     0x27
 #endif
@@ -91,8 +100,8 @@ extern "C" char *                    _simple_string(_SIMPLE_STRING __b);
 
 
 
-// 32-bit ppc and ARM are the only architecture that use cpu-sub-types
-#define CPU_SUBTYPES_SUPPORTED __ppc__ || __arm__
+// ARM is the only architecture that use cpu-sub-types
+#define CPU_SUBTYPES_SUPPORTED  __arm__
 
 
 
@@ -113,6 +122,8 @@ extern "C" {
 // implemented in dyldStartup.s for CrashReporter
 extern "C" void dyld_fatal_error(const char* errString) __attribute__((noreturn));
 
+// magic linker symbol for start of dyld binary
+extern "C" void* __dso_handle;
 
 
 //
@@ -175,6 +186,8 @@ typedef std::vector<dyld_image_state_change_handler> StateHandlers;
 struct RegisteredDOF { const mach_header* mh; int registrationID; };
 struct DylibOverride { const char* installName; const char* override; };
 
+enum RestrictedReason { restrictedNot, restrictedBySetGUid, restrictedBySegment, restrictedByEntitlements };
+       
 // all global state
 static const char*                                     sExecPath = NULL;
 static const macho_header*                     sMainExecutableMachHeader = NULL;
@@ -184,6 +197,7 @@ static cpu_subtype_t                                sHostCPUsubtype;
 #endif
 static ImageLoader*                                    sMainExecutable = NULL;
 static bool                                                    sProcessIsRestricted = false;
+static RestrictedReason                        sRestrictedReason = restrictedNot;
 static unsigned int                                    sInsertedDylibCount = 0;
 static std::vector<ImageLoader*>       sAllImages;
 static std::vector<ImageLoader*>       sImageRoots;
@@ -334,6 +348,7 @@ void throwf(const char* format, ...)
 
 
 //#define ALTERNATIVE_LOGFILE "/dev/console"
+
 static int sLogfile = STDERR_FILENO;
 
 #if LOG_BINDINGS
@@ -429,19 +444,8 @@ FileOpener::~FileOpener()
 }
 
 
-// forward declaration
-#if __ppc__ || __i386__
-bool isRosetta();
-#endif
-
-
 static void    registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
 {
-#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);
@@ -560,7 +564,7 @@ static void notifySingle(dyld_image_states state, const ImageLoader* image)
        if ( handlers != NULL ) {
                dyld_image_info info;
                info.imageLoadAddress   = image->machHeader();
-               info.imageFilePath              = image->getPath();
+               info.imageFilePath              = image->getRealPath();
                info.imageFileModDate   = image->lastModified();
                for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
                        const char* result = (*it)(state, 1, &info);
@@ -616,7 +620,7 @@ void syncAllImages()
                dyld_image_info info;
                ImageLoader* image = *it;
                info.imageLoadAddress = image->machHeader();
-               info.imageFilePath = image->getPath();
+               info.imageFilePath = image->getRealPath();
                info.imageFileModDate = image->lastModified();
                // add to all_image_infos if not already there
                bool found = false;
@@ -676,7 +680,7 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                                ImageLoader* image = images[i];
                                //dyld::log("  state=%d, name=%s\n", state, image->getPath());
                                p->imageLoadAddress = image->machHeader();
-                               p->imageFilePath = image->getPath();
+                               p->imageFilePath = image->getRealPath();
                                p->imageFileModDate = image->lastModified();
                                // special case for add_image hook
                                if ( state == dyld_image_state_bound )
@@ -758,6 +762,13 @@ static void clearAllDepths()
                (*it)->clearDepth();
 }
 
+static void printAllDepths()
+{
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
+               dyld::log("%03d %s\n",  (*it)->getDepth(), (*it)->getShortName());
+}
+
+
 static unsigned int imageCount()
 {
        return sAllImages.size();
@@ -949,16 +960,23 @@ ImageLoader* mainExecutable()
 
 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);
+       try {
+               const unsigned int imageCount = sImageFilesNeedingTermination.size();
+               for(unsigned int i=imageCount; i > 0; --i){
+                       ImageLoader* image = sImageFilesNeedingTermination[i-1];
+                       image->doTermination(gLinkContext);
+               }
+               sImageFilesNeedingTermination.clear();
+               notifyBatch(dyld_image_state_terminated);
+       }
+       catch (const char* msg) {
+               halt(msg);
        }
-       sImageFilesNeedingTermination.clear();
-       notifyBatch(dyld_image_state_terminated);
 }
 
 
+#if SUPPORT_VERSIONED_PATHS
+
 // forward reference
 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName);
 
@@ -1068,6 +1086,8 @@ static void checkFrameworkOverridesInDir(const char* dirPath)
                closedir(dirp);
        }
 }
+#endif // SUPPORT_VERSIONED_PATHS
+
 
 //
 // Turns a colon separated list of strings into a NULL terminated array 
@@ -1480,6 +1500,22 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                }
        }
        *d++ = NULL;
+       if ( removedCount != 0 ) {
+               dyld::log("dyld: DYLD_ environment variables being ignored because ");
+               switch (sRestrictedReason) {
+                       case restrictedNot:
+                               break;
+                       case restrictedBySetGUid:
+                               dyld::log("main executable (%s) is setuid or setgid\n", sExecPath);
+                               break;
+                       case restrictedBySegment:
+                               dyld::log("main executable (%s) has __RESTRICT/__restrict section\n", sExecPath);
+                               break;
+                       case restrictedByEntitlements:
+                               dyld::log("main executable (%s) is code signed with entitlements\n", sExecPath);
+                               break;
+               }
+       }
        
        // slide apple parameters
        if ( removedCount > 0 ) {
@@ -1562,6 +1598,15 @@ static void getHostInfo()
 #elif __ARM_ARCH_6K__
        sHostCPU                = CPU_TYPE_ARM;
        sHostCPUsubtype = CPU_SUBTYPE_ARM_V6;
+#elif __ARM_ARCH_7F__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7F;
+#elif __ARM_ARCH_7S__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7S;
+#elif __ARM_ARCH_7K__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
 #else
        struct host_basic_info info;
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
@@ -1742,31 +1787,19 @@ const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
 //
 
 
-#if __ppc__
-//      
-//     32-bit PowerPC sub-type lists
-//
-const int kPPC_RowCount = 4;
-static const cpu_subtype_t kPPC32[kPPC_RowCount][6] = { 
-       // G5 can run any code
-       {  CPU_SUBTYPE_POWERPC_970, CPU_SUBTYPE_POWERPC_7450,  CPU_SUBTYPE_POWERPC_7400, CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST },
-       
-       // G4 can run all but G5 code
-       {  CPU_SUBTYPE_POWERPC_7450,  CPU_SUBTYPE_POWERPC_7400,  CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
-       {  CPU_SUBTYPE_POWERPC_7400,  CPU_SUBTYPE_POWERPC_7450,  CPU_SUBTYPE_POWERPC_750, CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
-
-       // G3 cannot run G4 or G5 code
-       { CPU_SUBTYPE_POWERPC_750,  CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST,  CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST }
-};
-#endif
-
-
 #if __arm__
 //      
 //     ARM sub-type lists
 //
-const int kARM_RowCount = 5;
-static const cpu_subtype_t kARM[kARM_RowCount][6] = { 
+const int kARM_RowCount = 8;
+static const cpu_subtype_t kARM[kARM_RowCount][9] = { 
+
+       // armv7f can run: v7f, v7, v6, v5, and v4
+       {  CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+
+       // armv7k can run: v7k, v6, v5, and v4
+       {  CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+
        // armv7 can run: v7, v6, v5, and v4
        {  CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
        
@@ -1789,14 +1822,6 @@ static const cpu_subtype_t kARM[kARM_RowCount][6] = {
 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
 {
        switch (cpu) {
-#if __ppc__
-               case CPU_TYPE_POWERPC:
-                       for (int i=0; i < kPPC_RowCount ; ++i) {
-                               if ( kPPC32[i][0] == subtype )
-                                       return kPPC32[i];
-                       }
-                       break;
-#endif
 #if __arm__
                case CPU_TYPE_ARM:
                        for (int i=0; i < kARM_RowCount ; ++i) {
@@ -1851,15 +1876,6 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
        for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
                if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
                        switch (cpu) {
-#if __ppc__
-                               case CPU_TYPE_POWERPC:
-                                       if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_POWERPC_ALL ) {
-                                               *offset = OSSwapBigToHostInt32(archs[i].offset);
-                                               *len = OSSwapBigToHostInt32(archs[i].size);
-                                               return true;
-                                       }
-                                       break;
-#endif
 #if __arm__
                                case CPU_TYPE_ARM:
                                        if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM_ALL ) {
@@ -1952,12 +1968,6 @@ bool isCompatibleMachO(const uint8_t* firstPage, const char* path)
                        
                        // cpu type has no ordered list of subtypes
                        switch (mh->cputype) {
-                               case CPU_TYPE_POWERPC:
-                                       // 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:
                                case CPU_TYPE_X86_64:
                                        // subtypes are not used or these architectures
@@ -2257,6 +2267,7 @@ static ImageLoader* loadPhase5stat(const char* path, const LoadContext& context,
 {
        ImageLoader* image = NULL;
        *imageFound = false;
+       *statErrNo = 0;
        if ( stat(path, stat_buf) == 0 ) {
                // in case image was renamed or found via symlinks, check for inode match
                image = findLoadedImage(*stat_buf);
@@ -2304,7 +2315,7 @@ static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const
                // see if this image in the cache was already loaded via a different path
                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
                        ImageLoader* anImage = *it;
-                       if ( anImage->machHeader() == mhInCache )
+                       if ( (const macho_header*)anImage->machHeader() == mhInCache )
                                return anImage;
                }
                // do nothing if not already loaded and if RTLD_NOLOAD 
@@ -2329,7 +2340,7 @@ static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const
                return image;
 #endif
        // just return NULL if file not found, but record any other errors
-       if ( statErrNo != ENOENT ) {
+       if ( (statErrNo != ENOENT) && (statErrNo != 0) ) {
                exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, statErrNo));
        }
        return NULL;
@@ -2711,20 +2722,11 @@ ImageLoader* load(const char* path, const LoadContext& context)
 
 
 
-
 #if DYLD_SHARED_CACHE_SUPPORT
 
 
 
-
-#if __ppc__
-       #define ARCH_NAME                       "ppc"
-       #define ARCH_NAME_ROSETTA       "rosetta"
-       #define ARCH_CACHE_MAGIC        "dyld_v1     ppc"
-#elif __ppc64__
-       #define ARCH_NAME                       "ppc64"
-       #define ARCH_CACHE_MAGIC        "dyld_v1   ppc64"
-#elif __i386__
+#if __i386__
        #define ARCH_NAME                       "i386"
        #define ARCH_CACHE_MAGIC        "dyld_v1    i386"
 #elif __x86_64__
@@ -2741,6 +2743,14 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #elif __ARM_ARCH_6K__
        #define ARCH_NAME                       "armv6"
        #define ARCH_CACHE_MAGIC        "dyld_v1   armv6"
+#elif __ARM_ARCH_7F__
+       #define ARCH_NAME                       "armv7f"
+       #define ARCH_CACHE_MAGIC        "dyld_v1  armv7f"
+       #define SHARED_REGION_READ_ONLY_START   0x30000000
+       #define SHARED_REGION_READ_ONLY_END     0x3E000000
+       #define SHARED_REGION_WRITABLE_START    0x3E000000
+       #define SHARED_REGION_WRITABLE_END      0x40000000
+       #define SLIDEABLE_CACHE_SUPPORT             1
 #elif __ARM_ARCH_7A__
        #define ARCH_NAME                       "armv7"
        #define ARCH_CACHE_MAGIC        "dyld_v1   armv7"
@@ -2749,12 +2759,20 @@ ImageLoader* load(const char* path, const LoadContext& context)
        #define SHARED_REGION_WRITABLE_START    0x3E000000
        #define SHARED_REGION_WRITABLE_END      0x40000000
        #define SLIDEABLE_CACHE_SUPPORT             1
+#elif __ARM_ARCH_7K__
+       #define ARCH_NAME                       "armv7k"
+       #define ARCH_CACHE_MAGIC        "dyld_v1  armv7k"
+       #define SHARED_REGION_READ_ONLY_START   0x30000000
+       #define SHARED_REGION_READ_ONLY_END     0x3E000000
+       #define SHARED_REGION_WRITABLE_START    0x3E000000
+       #define SHARED_REGION_WRITABLE_END      0x40000000
+       #define SLIDEABLE_CACHE_SUPPORT             1
 #endif
 
 
 static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_address)
 {
-       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) ) 
+       if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion ) 
                return syscall(294, start_address);
        return -1;
 }
@@ -2775,7 +2793,7 @@ static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uin
                        dyld::log("dyld: code signature for shared cache failed with errno=%d\n", errno);
        }
 #endif
-       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) ) {
+       if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion ) {
                return syscall(438, fd, count, mappings, slide, slideInfo, slideInfoSize);
        }
 
@@ -2861,13 +2879,7 @@ int openSharedCacheFile()
        char path[1024];
        strcpy(path, sSharedCacheDir);
        strcat(path, "/");
-#if __ppc__
-       // rosetta cannot handle optimized _ppc cache, so it use _rosetta cache instead, rdar://problem/5495438
-    if ( isRosetta() )
-               strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_ROSETTA);
-    else
-#endif
-               strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
+       strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
        return ::open(path, O_RDONLY);
 }
 
@@ -3158,8 +3170,7 @@ static void mapSharedCache()
                // check for file that enables dyld shared cache dylibs to be overridden
                struct stat enableStatBuf;
                sDylibsOverrideCache = ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
-#endif         
-
+#endif 
        }
 }
 #endif // #if DYLD_SHARED_CACHE_SUPPORT
@@ -3475,14 +3486,19 @@ void registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_s
        // add to list of handlers
        std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
        if ( handlers != NULL ) {
-               handlers->push_back(handler);
+        // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
+        // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
+        if ( state == dyld_image_state_mapped )
+            handlers->insert(handlers->begin(), handler);
+        else
+            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.imageFilePath              = image->getRealPath();
                        info.imageFileModDate   = image->lastModified();
                        // should only call handler if state == image->state
                        if ( image->getState() == state )
@@ -3557,6 +3573,7 @@ static void setContext(const macho_header* mainExecutableMH, int argc, const cha
        gLinkContext.removeImage                        = &removeImage;
        gLinkContext.registerDOFs                       = &registerDOFs;
        gLinkContext.clearAllDepths                     = &clearAllDepths;
+       gLinkContext.printAllDepths                     = &printAllDepths;
        gLinkContext.imageCount                         = &imageCount;
        gLinkContext.setNewProgramVars          = &setNewProgramVars;
 #if DYLD_SHARED_CACHE_SUPPORT
@@ -3583,21 +3600,6 @@ static void setContext(const macho_header* mainExecutableMH, int argc, const cha
        gLinkContext.sharedRegionMode           = ImageLoader::kUseSharedRegion;
 }
 
-#if __ppc__ || __i386__
-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
-
 
 #if __LP64__
        #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
@@ -3644,7 +3646,7 @@ static bool hasRestrictedSegment(const macho_header* mh)
        return false;
 }
 
-
+#if SUPPORT_VERSIONED_PATHS
 //
 // Peeks at a dylib file and returns its current_version and install_name.
 // Returns false on error.
@@ -3706,7 +3708,8 @@ static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* versi
        
        return false;
 }
-                                                               
+#endif // SUPPORT_VERSIONED_PATHS
+                                               
 #if 0
 static void printAllImages()
 {
@@ -3758,8 +3761,14 @@ void garbageCollectImages()
                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
                        ImageLoader* image = *it;
                        if ( (image->referenceCount() == 0) && !image->neverUnload() && !image->isBeingRemoved() ) {
+                               if ( image->isReferencedUpward() ) {
+                                       // temp hack for rdar://problem/10973109
+                                       // if an image is upwardly referenced, we really need to scan all images 
+                                       // to see if any are still using it.
+                                       continue;
+                               }
                                try {
-                                       //dyld::log("garbageCollectImages: deleting %s\n", image->getPath());
+                                       //dyld::log("garbageCollectImages: deleting %p %s\n", image, image->getPath());
                                        image->setBeingRemoved();
                                        removeImage(image);
                                        ImageLoader::deleteImage(image);
@@ -3828,14 +3837,18 @@ static void loadInsertedDylib(const char* path)
 static bool processRestricted(const macho_header* mainExecutableMH)
 {
     // all processes with setuid or setgid bit set are restricted
-    if ( issetugid() )
-        return true;
-        
-       if ( hasRestrictedSegment(mainExecutableMH) && (geteuid() != 0) ) {
+    if ( issetugid() ) {
+               sRestrictedReason = restrictedBySetGUid;
+               return true;
+       }
+               
+       const uid_t euid = geteuid();
+       if ( (euid != 0) && hasRestrictedSegment(mainExecutableMH) ) {
                // existence of __RESTRICT/__restrict section make process restricted
+               sRestrictedReason = restrictedBySegment;
                return true;
        }
-    
+       
 #if __MAC_OS_X_VERSION_MIN_REQUIRED    
     // ask kernel if code signature of program makes it restricted
     uint32_t flags;
@@ -3844,14 +3857,42 @@ static bool processRestricted(const macho_header* mainExecutableMH)
                 CS_OPS_STATUS,
                 &flags,
                 sizeof(flags)) != -1) {
-        if (flags & CS_RESTRICT)
-            return true;
+        if (flags & CS_RESTRICT) {
+                       sRestrictedReason = restrictedByEntitlements;
+                       return true;
+               }
     }
 #endif
     return false;
 }
 
 
+
+
+// <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
+static void addDyldImageToUUIDList()
+{
+       const struct macho_header* mh = (macho_header*)&__dso_handle;
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_UUID: {
+                               uuid_command* uc = (uuid_command*)cmd;
+                               dyld_uuid_info info;
+                               info.imageLoadAddress = (mach_header*)mh;
+                               memcpy(info.imageUUID, uc->uuid, 16);
+                               addNonSharedCacheImageUUID(info);
+                               return;
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+}
+
+
+
 //
 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which
 // sets up some registers and call this function.
@@ -3859,8 +3900,11 @@ static bool processRestricted(const macho_header* mainExecutableMH)
 // Returns address of main() in target program which __dyld_start jumps to
 //
 uintptr_t
-_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
+_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, 
+               int argc, const char* argv[], const char* envp[], const char* apple[], 
+               uintptr_t* startGlue)
 {      
+       uintptr_t result = 0;
        CRSetCrashLogMessage("dyld: launch started");
 #ifdef ALTERNATIVE_LOGFILE
        sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
@@ -3894,16 +3938,6 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
        // Pickup the pointer to the exec path.
        sExecPath = apple[0];
        bool ignoreEnvironmentVariables = false;
-#if __i386__
-       if ( isRosetta() ) {
-               // under Rosetta (x86 side)
-               // When a 32-bit ppc program is run under emulation on an Intel processor,
-               // 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;
-               ignoreEnvironmentVariables = true;
-       }
-#endif
        if ( sExecPath[0] != '/' ) {
                // have relative path, use cwd to make absolute
                char cwdbuff[MAXPATHLEN];
@@ -3916,7 +3950,6 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                        sExecPath = s;
                }
        }
-       uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
     sProcessIsRestricted = processRestricted(mainExecutableMH);
     if ( sProcessIsRestricted ) {
@@ -3954,6 +3987,8 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
 #endif
        
        try {
+               // add dyld itself to UUID list
+               addDyldImageToUUIDList();
                CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
                // instantiate ImageLoader for main executable
                sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
@@ -3983,7 +4018,6 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                        gLinkContext.bindFlat = true;
                        gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
                }
-               result = (uintptr_t)sMainExecutable->getMain();
 
                // link any inserted libraries
                // do this after linking main executable so that any dylibs pulled in by inserted 
@@ -4001,8 +4035,25 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
        #if SUPPORT_OLD_CRT_INITIALIZATION
                // Old way is to run initializers via a callback from crt1.o
                if ( ! gRunInitializersOldWay ) 
+                       initializeMainExecutable(); 
+       #else
+               // run all initializers
+               initializeMainExecutable(); 
        #endif
-               initializeMainExecutable(); // run all initializers
+               // find entry point for main executable
+               result = (uintptr_t)sMainExecutable->getThreadPC();
+               if ( result != 0 ) {
+                       // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib
+                       if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 9) )
+                               *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
+                       else
+                               halt("libdyld.dylib support not present for LC_MAIN");
+               }
+               else {
+                       // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
+                       result = (uintptr_t)sMainExecutable->getMain();
+                       *startGlue = NULL;
+               }
        }
        catch(const char* message) {
                syncAllImages();
index 9ad1ef8b7ea139da70dff3a0ca3cfc497e507a17..19b4431c14d4c1406ac051afa7f136bd288ea3ac 100644 (file)
@@ -88,7 +88,8 @@ namespace dyld {
        extern void                                     removeImage(ImageLoader* image);
        extern ImageLoader*                     cloneImage(ImageLoader* image);
        extern void                                     forEachImageDo( void (*)(ImageLoader*, void*), void*);
-       extern uintptr_t                        _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[]);
+       extern uintptr_t                        _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], 
+                                                                               const char* apple[], uintptr_t* startGlue);
        extern void                                     halt(const char* message)  __attribute__((noreturn));
        extern void                                     setErrorMessage(const char* msg);
        extern const char*                      getErrorMessage();
index 0d0dbc73219f89599803fd302cf72cd1cf03f989..d00118448979ebf78a5f29f40c18910f38131eb7 100644 (file)
@@ -80,8 +80,7 @@ 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 (__ppc__ || __i386__)
-
+#define OLD_LIBSYSTEM_SUPPORT (__i386__)
 
 // The following functions have no prototype in any header.  They are special cases
 // where _dyld_func_lookup() is used directly.
@@ -334,7 +333,7 @@ const char* _dyld_get_image_name(uint32_t image_index)
                dyld::log("%s(%u)\n", __func__, image_index);
        ImageLoader* image = dyld::getIndexedImage(image_index);
        if ( image != NULL )
-               return image->getPath();
+               return image->getRealPath();
        else
                return NULL;
 }
@@ -582,7 +581,7 @@ const struct mach_header* NSAddImage(const char* path, uint32_t 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|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) == 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);
 }
@@ -1188,8 +1187,6 @@ void _dyld_fork_child()
        dyld_all_image_infos.systemOrderFlag = 0;
 }
 
-
-
 typedef void (*MonitorProc)(char *lowpc, char *highpc);
 
 static void monInitCallback(ImageLoader* image, void* userData)
@@ -1584,7 +1581,7 @@ int dladdr(const void* address, Dl_info* info)
        CRSetCrashLogMessage("dyld: in dladdr()");
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
-               info->dli_fname = image->getPath();
+               info->dli_fname = image->getRealPath();
                info->dli_fbase = (void*)image->machHeader();
                if ( address == info->dli_fbase ) {
                        // special case lookup of header
@@ -1595,6 +1592,13 @@ int dladdr(const void* address, Dl_info* info)
                }
                // find closest symbol in the image
                info->dli_sname = image->findClosestSymbol(address, (const void**)&info->dli_saddr);
+               // never return the mach_header symbol
+               if ( info->dli_saddr == info->dli_fbase ) {
+                       info->dli_sname = NULL;
+                       info->dli_saddr = NULL;
+                       CRSetCrashLogMessage(NULL);
+                       return 1; // success
+               }
                if ( info->dli_sname != NULL ) {
                        if ( info->dli_sname[0] == '_' )
                                info->dli_sname = info->dli_sname +1; // strip off leading underscore
@@ -1675,15 +1679,7 @@ void* dlsym(void* handle, const char* symbolName)
        
        // magic "search what I would see" handle
        if ( handle == RTLD_NEXT ) {
-#if __ppc__
-               // <rdar://problem/7628929> work around for llvmgcc bug
-               void* fa = __builtin_frame_address(0);
-               fa = *(void**)fa;
-               fa = *(void**)fa;
-               void* callerAddress = *((void**)(((int)fa)+8));
-#else  
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
-#endif
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
                sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
                if ( sym != NULL ) {
@@ -1782,7 +1778,7 @@ const char* dyld_image_path_containing_address(const void* address)
 
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL )
-               return image->getPath();
+               return image->getRealPath();
        return NULL;
 }
 
index cb99cdd75564ebfde28062a1c3884bb3439efe76..0417585d684bfd9da642327b3246ac3b6e6f5eaf 100644 (file)
 extern "C" int  __cxa_atexit(void (*func)(void *), void *arg, void *dso);
 extern "C" void __cxa_finalize(const void *dso);
 
+
+#ifndef LC_VERSION_MIN_MACOSX
+       #define LC_VERSION_MIN_MACOSX 0x24
+       struct version_min_command {
+               uint32_t        cmd;            /* LC_VERSION_MIN_MACOSX or
+                                          LC_VERSION_MIN_IPHONEOS  */
+               uint32_t        cmdsize;        /* sizeof(struct min_version_command) */
+               uint32_t        version;        /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+               uint32_t        sdk;            /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+       };
+#endif
+
+#ifndef LC_VERSION_MIN_IPHONEOS
+       #define LC_VERSION_MIN_IPHONEOS 0x25
+#endif
+
+
 #ifndef LC_LOAD_UPWARD_DYLIB
        #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
 #endif
 
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__ || __arm__)
+#define DYLD_SHARED_CACHE_SUPPORT (__i386__ || __x86_64__ || __arm__)
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
@@ -406,6 +423,119 @@ const char* libraryName)
        return(-1);
 }
 
+
+/*
+ * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the
+ * specified binary was built against.
+ *
+ * First looks for LC_VERSION_MIN_MACOSX/LC_VERSION_MIN_IPHONEOS
+ * in binary and if sdk field is not zero, return that value.
+ * Otherwise, looks for the libSystem.B.dylib the binary linked
+ * against and uses a table to convert that to an sdk version.
+ */
+uint32_t dyld_get_sdk_version(const mach_header* mh)
+{
+#if __LP64__
+       const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
+#else
+       const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header));
+#endif
+       const version_min_command* versCmd;
+       const dylib_command* dylibCmd;
+       const load_command* cmd = cmds;
+       uint32_t libSystemVers = 0;
+       for(uint32_t i = 0; i < mh->ncmds; ++i) {
+               switch ( cmd->cmd ) { 
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                               versCmd = (version_min_command*)cmd;
+                               if ( versCmd->sdk != 0 )
+                                       return versCmd->sdk;    // found explicit SDK version
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
+                               dylibCmd = (dylib_command*)cmd;
+                               if ( strcmp((char*)dylibCmd + dylibCmd->dylib.name.offset, "/usr/lib/libSystem.B.dylib") == 0 )
+                                       libSystemVers = dylibCmd->dylib.current_version;
+                               else if ( strcmp((char*)dylibCmd + dylibCmd->dylib.name.offset, "/usr/lib/libSystem.dylib") == 0 )
+                                       return 0x00040000; // all iOS simulator have same libSystem.dylib version
+                               break;
+               }
+           cmd = (load_command*)((char *)cmd + cmd->cmdsize);
+       }
+       
+       if ( libSystemVers != 0 ) {
+               // found linked libSystem.B.dylib version linked against
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+               // convert libSystem.B.dylib version to iOS sdk version
+               if ( libSystemVers < 0x006F0010 )       // libSystem 111.0.16 in 3.0
+                       return 0x00020000;              // 2.0  
+               else if ( libSystemVers < 0x006F0201 )  // libSystem 111.2.1 in 3.1
+                       return 0x00030000;              // 3.0  
+               else if ( libSystemVers < 0x007D020B )  // libSystem 125.2.11 in 4.0
+                       return 0x00030100;              // 3.1  
+               else if ( libSystemVers < 0x007D0400 )  // libSystem 125.4 in 4.1 and in 4.2
+                       return 0x00040000;              // 4.0  
+               else if ( libSystemVers < 0x009F0000 )  // libSystem 159 in 4.3
+                       return 0x00040100;              // 4.1  
+               else if ( libSystemVers < 0x00A10000 )  // libSystem 161 in 5.0
+                       return 0x00040300;              // 4.3  
+               else
+                       return 0x00050000;
+#else
+               // convert libSystem.B.dylib version to MacOSX sdk version
+               if ( libSystemVers < 0x006F0000 )       // libSystem 111 in 10.5
+                       return 0x000A0400;              // 10.4  
+               else if ( libSystemVers < 0x007B0000 )  // libSystem 123 in 10.6
+                       return 0x000A0500;              // 10.5  
+               else if ( libSystemVers < 0x009F0000 )  // libSystem 159 in 10.7
+                       return 0x000A0600;              // 10.6  
+               else if ( libSystemVers < 0x00A10000 )  // libSystem 161 in 10.8
+                       return 0x000A0700;              // 10.7  
+               else 
+                       return 0x000A0800;              // 10.8  
+#endif
+       }
+       
+       return 0;
+}
+
+uint32_t dyld_get_program_sdk_version()
+{
+       return dyld_get_sdk_version((mach_header*)_NSGetMachExecuteHeader());
+}
+
+
+uint32_t dyld_get_min_os_version(const struct mach_header* mh)
+{
+#if __LP64__
+       const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
+#else
+       const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header));
+#endif
+       const version_min_command* versCmd;
+       const load_command* cmd = cmds;
+       for(uint32_t i = 0; i < mh->ncmds; ++i) {
+               switch ( cmd->cmd ) { 
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                               versCmd = (version_min_command*)cmd;
+                               return versCmd->version;        // found explicit min OS version
+                               break;
+               }
+           cmd = (load_command*)((char *)cmd + cmd->cmdsize);
+       }
+       return 0;
+}
+
+
+uint32_t dyld_get_program_min_os_version()
+{
+       return dyld_get_min_os_version((mach_header*)_NSGetMachExecuteHeader());
+}
+
+
 #if DEPRECATED_APIS_SUPPORTED
 /*
  * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the
@@ -1075,9 +1205,10 @@ static void shared_cache_out_of_date()
 }
 #endif // DYLD_SHARED_CACHE_SUPPORT
 
+extern void* start;
 
 // the table passed to dyld containing thread helpers
-static dyld::LibSystemHelpers sHelpers = { 8, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
+static dyld::LibSystemHelpers sHelpers = { 9, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
                                                                        &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
                                                #if DYLD_SHARED_CACHE_SUPPORT
                                                                        &shared_cache_missing, &shared_cache_out_of_date,
@@ -1088,7 +1219,8 @@ static dyld::LibSystemHelpers sHelpers = { 8, &dyldGlobalLockAcquire, &dyldGloba
                                                                        &pthread_key_create, &pthread_setspecific,
                                                                        &malloc_size,
                                                                        &pthread_getspecific,
-                                                                       &__cxa_finalize};
+                                                                       &__cxa_finalize,
+                                                                       &start};
 
 
 //
index cff7dbe7474d1d66e7e49d162bed3384b295d2b9..2520f8fac505943c64dcc6ef06bfae082b20fe38 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -96,51 +96,31 @@ char* __cxa_get_globals_fast()
 
 
 
-#if __x86_64__ || __i386__ || __ppc__
+#if !__arm__
 //
-//  The intel/ppc versions of dyld uses zero-cost exceptions which are handled by
+//  The intel versions of dyld uses zero-cost exceptions which are handled by
 //  linking with a special copy of libunwind.a
 //
 
-static struct dyld_unwind_sections     sDyldInfo;
-static void*                                           sDyldTextEnd;
+extern void*  ehStart  __asm("section$start$__TEXT$__eh_frame");
+extern void*  ehEnd    __asm("section$end$__TEXT$__eh_frame");
+extern void*  uwStart  __asm("section$start$__TEXT$__unwind_info");
+extern void*  uwEnd    __asm("section$end$__TEXT$__unwind_info");
 
-// called by dyldStartup.s very early
-void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
-{
-       // record location of unwind sections in dyld itself
-    sDyldInfo.mh = mh;    
-       const struct load_command* cmd;
-       unsigned long i;
-       cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
-       for(i = 0; i < mh->ncmds; i++) {
-           if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-                       if ( strcmp(seg->segname, "__TEXT") == 0 ) {
-                               const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
-                               unsigned long j;
-                               for (j = 0; j < seg->nsects; j++) {
-                                       if ( strcmp(sect[j].sectname, "__eh_frame") == 0 ) {
-                                               sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide);
-                                               sDyldInfo.dwarf_section_length = sect[j].size;
-                                       }
-                                       else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) {
-                                               sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide);
-                                               sDyldInfo.compact_unwind_section_length = sect[j].size;
-                                       }
-                               }
-                               sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide);
-                   }
-               }
-           cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
-       }
-}
+extern void*  textStart __asm("section$start$__TEXT$__text");
+extern void*  textEnd   __asm("section$end$__TEXT$__text");
 
-// called by libuwind code to find unwind information in dyld
+extern void* __dso_handle;
+
+// called by libuwind code to find unwind information sections in dyld
 bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
 {
-       if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) { 
-               *info = sDyldInfo;
+       if ( ((void*)&textStart < addr) && (addr < (void*)&textEnd) ) { 
+        info->mh = (struct mach_header*)&__dso_handle;
+        info->dwarf_section = &ehStart;
+        info->dwarf_section_length = ((char*)&ehEnd - (char*)&ehStart);
+        info->compact_unwind_section = &uwStart;
+        info->compact_unwind_section_length = ((char*)&uwEnd - (char*)&uwStart);
                return true;
        }
        else {
@@ -148,13 +128,7 @@ bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
        }
 }
 
-#if __ppc__
-       // the ppc version of _Znwm in libstdc++.a uses keymgr
-       // need to override that
-       void* _Znwm(size_t size) { return malloc(size); }
-#endif
-
-#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
+#endif // !__arm__
 
 
 #if __arm__
@@ -166,13 +140,6 @@ struct _Unwind_FunctionContext
 
 };
 
-//
-//  The ARM of dyld use SL-LJ based exception handling
-//  which does not require any initialization until libSystem is initialized.
-//
-void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
-{
-}
 
 static pthread_key_t                                           sThreadChainKey = 0; 
 static struct _Unwind_FunctionContext*         sStaticThreadChain = NULL; 
index e40b1e84c7159a986ca3651a5cf20af8f0e0bee2..a1266d7f68cf221e276d40c86aa737911abcd23c 100644 (file)
@@ -31,9 +31,6 @@
 #include <mach-o/loader.h>
 #include <mach-o/ldsyms.h>
 #include <mach-o/reloc.h>
-#if __ppc__ || __ppc64__
-       #include <mach-o/ppc/reloc.h>
-#endif
 #if __x86_64__
        #include <mach-o/x86_64/reloc.h>
 #endif
@@ -192,10 +189,6 @@ static void rebaseDyld(const struct macho_header* mh, intptr_t slide)
        const relocation_info* const relocsStart = (struct relocation_info*)(linkEditSeg->vmaddr + slide + dynamicSymbolTable->locreloff - linkEditSeg->fileoff);
        const relocation_info* const relocsEnd = &relocsStart[dynamicSymbolTable->nlocrel];
        for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
-       #if __ppc__ || __ppc64__ || __i36__
-               if ( (reloc->r_address & R_SCATTERED) != 0 )
-                       throw "scattered relocation in dyld";
-       #endif
                if ( reloc->r_length != RELOC_SIZE ) 
                        throw "relocation in dyld has wrong size";
 
@@ -208,7 +201,6 @@ static void rebaseDyld(const struct macho_header* mh, intptr_t slide)
 }
 
 
-extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp
 extern "C" void mach_init();
 
 //
@@ -228,7 +220,8 @@ extern "C" {
 //  In dyld we have to do this manually.
 //
 uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], 
-                                                               intptr_t slide, const struct macho_header* dyldsMachHeader)
+                               intptr_t slide, const struct macho_header* dyldsMachHeader,
+                               uintptr_t* startGlue)
 {
        // if kernel had to slide dyld, we need to fix up load sensitive locations
        // we have to do this before using any global variables
@@ -242,9 +235,6 @@ uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char*
        _pthread_keys_init();
 #endif
 
-       // enable C++ exceptions to work inside dyld
-       dyld_exceptions_init(dyldsMachHeader, slide);
-       
        // allow dyld to use mach messaging
        mach_init();
 
@@ -261,7 +251,7 @@ uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char*
                
        // now that we are done bootstrapping dyld, call dyld's main
        uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader);
-       return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple);
+       return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue);
 }
 
 
index bbd8b01389693dfb44b648e7c34de566cebb1536..0fdda05463285b194576c80ccd81c375c4f0576d 100644 (file)
  */
 
 #include <Availability.h>
+#include <stddef.h>
 
 //
 // This is the temporary private interface between libSystem.B.dylib and dyld
 //
 
+
+int          NXArgc = 0;
+const char** NXArgv = NULL;
+const char** environ = NULL;
+const char*  __progname = NULL;
+
+
+
 //
 // Long ago, the compiler driver added -ldylib1.o to every dylib which caused a
 // __DATA,__dyld section to be added every dylib.  The new LINKEDIT format no longer requires
 // to some sort of vtable based interface, libdyld still needs a __DATA,__dyld section.
 // The code below adds that section.
 //
-struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
+struct __DATA__dyld { 
+       long                    lazy; 
+       int                             (*lookup)(const char*, void**);
+       // ProgramVars
+       const void*             mh;
+       int*                    NXArgcPtr;
+       const char***   NXArgvPtr;
+       const char***   environPtr;
+       const char**    __prognamePtr;
+};
 
-static volatile struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, 0 };
+static volatile struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) 
+       = { 0, 0, NULL, &NXArgc, &NXArgv, &environ, &__progname };
 
 #if __arm__ && __MAC_OS_X_VERSION_MIN_REQUIRED
 // <rdar://problem/8755380>
@@ -54,5 +73,3 @@ int _dyld_func_lookup(const char* dyld_func_name, void **address)
 }
 
 
-
-
index 874c49782eec0fe0e0c3daf4295bb4bdb69c34f7..9a5fd6085c8e95d4ce5363e769fcca37d1393602 100644 (file)
@@ -61,6 +61,8 @@ namespace dyld {
                void*           (*pthread_getspecific)(pthread_key_t);
                // added in version 8
                void            (*cxa_finalize)(const void*);
+               // added in version 9
+               void*           startGlueToCallExit;
        };
 #if __cplusplus
 };
index cf296ef3c69d0ec9fd43b55a805d2ebc5fbcbabf..11c8f1ff123e5a5606aa2e6aebaf11caf70a6686 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,7 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 /*
- * C runtime startup for i386 and ppc interface to the dynamic linker.
+ * C runtime startup for interface to the dynamic linker.
  * This is the same as the entry point in crt0.o with the addition of the
  * address of the mach header passed as the an extra first argument.
  *
@@ -111,37 +111,57 @@ _offset_to_dyld_all_image_infos:
        .align  4, 0x90
        .globl __dyld_start
 __dyld_start:
+       popl    %edx            # edx = mh of app
        pushl   $0              # push a zero for debugger end of frames marker
        movl    %esp,%ebp       # pointer to base of kernel frame
        andl    $-16,%esp       # force SSE alignment
+       subl    $32,%esp        # room for locals and outgoing parameters
        
-       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
-       subl    $12,%esp
        call    L__dyld_start_picbase
 L__dyld_start_picbase: 
        popl    %ebx            # set %ebx to runtime value of picbase
+
        movl    Lmh-L__dyld_start_picbase(%ebx), %ecx # ecx = prefered load address
        movl    __dyld_start_static_picbase-L__dyld_start_picbase(%ebx), %eax
        subl    %eax, %ebx      # ebx = slide = L__dyld_start_picbase - [__dyld_start_static_picbase]
        addl    %ebx, %ecx      # ecx = actual load address
-       pushl   %ecx            # param5 = actual load address
-       pushl   %ebx            # param4 = slide
-       lea     12(%ebp),%ebx   
-       pushl   %ebx            # param3 = argv
-       movl    8(%ebp),%ebx    
-       pushl   %ebx            # param2 = argc
-       movl    4(%ebp),%ebx    
-       pushl   %ebx            # param1 = mh
-       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
-
-       # clean up stack and jump to result
+       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh, &startGlue)
+       movl    %edx,(%esp)     # param1 = app_mh
+       movl    4(%ebp),%eax    
+       movl    %eax,4(%esp)    # param2 = argc
+       lea     8(%ebp),%eax    
+       movl    %eax,8(%esp)    # param3 = argv
+       movl    %ebx,12(%esp)   # param4 = slide
+       movl    %ecx,16(%esp)   # param5 = actual load address
+       lea     28(%esp),%eax
+       movl    %eax,20(%esp)   # param6 = &startGlue
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_Pm   
+       movl    28(%esp),%edx
+       cmpl    $0,%edx
+       jne     Lnew
+
+       # clean up stack and jump to "start" in main executable
        movl    %ebp,%esp       # restore the unaligned stack pointer
-       addl    $8,%esp         # remove the mh argument, and debugger end
-                               #  frame marker
+       addl    $4,%esp         # remove debugger end frame marker
        movl    $0,%ebp         # restore ebp back to zero
        jmp     *%eax           # jump to the entry point
 
-
+       # LC_MAIN case, set up stack for call to main() 
+Lnew:  movl    4(%ebp),%ebx
+       movl    %ebx,(%esp)     # main param1 = argc
+       leal    8(%ebp),%ecx
+       movl    %ecx,4(%esp)    # main param2 = argv
+       leal    0x4(%ecx,%ebx,4),%ebx
+       movl    %ebx,8(%esp)    # main param3 = env
+Lapple:        movl    (%ebx),%ecx     # look for NULL ending env[] array
+       add     $4,%ebx
+       testl   %ecx,%ecx
+       jne     Lapple          # once found, next pointer is "apple" parameter now in %ebx
+       movl    %ebx,12(%esp)   # main param4 = apple
+       pushl   %edx            # simulate return address into _start in libdyld
+       jmp     *%eax           # jump to main(argc,argv,env,apple) with return address set to _start
+       
+       
        .globl dyld_stub_binding_helper
 dyld_stub_binding_helper:
        hlt
@@ -182,105 +202,50 @@ _offset_to_dyld_all_image_infos:
        .align 2,0x90
        .globl __dyld_start
 __dyld_start:
+       popq    %rdi            # param1 = mh of app
        pushq   $0              # push a zero for debugger end of frames marker
        movq    %rsp,%rbp       # pointer to base of kernel frame
        andq    $-16,%rsp       # force SSE alignment
+       subq    $16,%rsp        # room for local variables
        
-       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
-       movq    8(%rbp),%rdi    # param1 = mh into %rdi
-       movl    16(%rbp),%esi   # param2 = argc into %esi
-       leaq    24(%rbp),%rdx   # param3 = &argv[0] into %rdx
+       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh, &startGlue)
+       movl    8(%rbp),%esi    # param2 = argc into %esi
+       leaq    16(%rbp),%rdx   # param3 = &argv[0] into %rdx
        movq    __dyld_start_static(%rip), %r8
        leaq    __dyld_start(%rip), %rcx
        subq     %r8, %rcx      # param4 = slide into %rcx
        leaq    ___dso_handle(%rip),%r8 # param5 = dyldsMachHeader
-       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
+       leaq    -8(%rbp),%r9
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_Pm
+       movq    -8(%rbp),%rdi
+       cmpq    $0,%rdi
+       jne     Lnew
 
-       # clean up stack and jump to result
+       # clean up stack and jump to "start" in main executable
        movq    %rbp,%rsp       # restore the unaligned stack pointer
-       addq    $16,%rsp        # remove the mh argument, and debugger end frame marker
+       addq    $8,%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
        
+       # LC_MAIN case, set up stack for call to main() 
+Lnew:  addq    $16,%rsp        # remove local variables
+       pushq   %rdi            # simulate return address into _start in libdyld
+       movq    8(%rbp),%rdi    # main param1 = argc into %rdi
+       leaq    16(%rbp),%rsi   # main param2 = &argv[0] into %rsi
+       leaq    0x8(%rsi,%rdi,8),%rdx # main param3 = &env[0] into %rdx
+       movq    %rdx,%rcx
+Lapple: movq   (%rcx),%r8
+       add     $8,%rcx
+       testq   %r8,%r8         # look for NULL ending env[] array
+       jne     Lapple          # main param4 = apple into %rcx
+       jmp     *%rax           # jump to main(argc,argv,env,apple) with return address set to _start
+       
 #endif /* __x86_64__ */
 
 
-#if __ppc__ || __ppc64__
-#include <architecture/ppc/mode_independent_asm.h>
-
-       .data
-       .align 2
-__dyld_start_static_picbase: 
-       .g_long     L__dyld_start_picbase
-Lmh:   .g_long     ___dso_handle
-
-#if __ppc__    
-       .set L_mh_offset,0
-       .set L_argc_offset,4
-       .set L_argv_offset,8
-#else
-       .set L_mh_offset,0
-       .set L_argc_offset,8    ; stack is 8-byte aligned and there is a 4-byte hole between argc and argv
-       .set L_argv_offset,16
-#endif
-
-       .text
-       .align 2
-; stable entry points into dyld
-       .globl  _stub_binding_helper
-_stub_binding_helper:
-       b       _stub_binding_helper_interface
-       nop 
-       .globl  _dyld_func_lookup
-_dyld_func_lookup:
-       b       __Z18lookupDyldFunctionPKcPm
-       nop 
-_offset_to_dyld_all_image_infos:
-       .long   _dyld_all_image_infos - . + 0x1010 
-       .long   0
-       # space for future stable entry points
-       .space  16
-       
-       
-       .text
-       .align 2
-__dyld_start:
-       mr      r26,r1          ; save original stack pointer into r26
-       subi    r1,r1,GPR_BYTES ; make space for linkage
-       clrrgi  r1,r1,5         ; align to 32 bytes
-       addi    r0,0,0          ; load 0 into r0
-       stg     r0,0(r1)        ; terminate initial stack frame
-       stgu    r1,-SF_MINSIZE(r1); allocate minimal stack frame
-               
-       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
-       lg      r3,L_mh_offset(r26)     ; r3 = mach_header
-       lwz     r4,L_argc_offset(r26)   ; r4 = argc (int == 4 bytes)
-       addi    r5,r26,L_argv_offset    ; r5 = argv
-       bcl     20,31,L__dyld_start_picbase     
-L__dyld_start_picbase: 
-       mflr    r31             ; put address of L__dyld_start_picbase in r31
-       addis   r6,r31,ha16(__dyld_start_static_picbase-L__dyld_start_picbase)
-       lg      r6,lo16(__dyld_start_static_picbase-L__dyld_start_picbase)(r6)
-       subf    r6,r6,r31       ; r6 = slide
-       addis   r7,r31,ha16(Lmh-L__dyld_start_picbase)
-       lg      r7,lo16(Lmh-L__dyld_start_picbase)(r7)
-       add     r7,r6,r7        ; r7 = dyld_mh
-       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
-       
-       ; clean up stack and jump to result
-       mtctr   r3              ; Put entry point in count register
-       mr      r12,r3          ;  also put in r12 for ABI convention.
-       addi    r1,r26,GPR_BYTES; Restore the stack pointer and remove the
-                               ;  mach_header argument.
-       bctr                    ; jump to the program's entry point
-
-       .globl dyld_stub_binding_helper
-dyld_stub_binding_helper:
-       trap
-L_end:
-#endif /* __ppc__ */
 
 #if __arm__
+       .syntax unified
        .data
        .align 2
 __dyld_start_static_picbase: 
@@ -318,10 +283,10 @@ ___dso_handle:    .long 0
        .align 2
 __dyld_start:
        mov     r8, sp          // save stack pointer
-       sub     sp, #8          // make room for outgoing dyld_mh parameter
+       sub     sp, #16         // make room for outgoing parameters
        bic     sp, sp, #7      // force 8-byte alignment
 
-       // call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
+       // call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh, &startGlue)
 
        ldr     r3, L__dyld_start_picbase_ptr
 L__dyld_start_picbase:
@@ -334,15 +299,33 @@ L__dyld_start_picbase:
        add     r2, r8, #8      // r2 = argv
 
        ldr     r4, Lmh
-L3:    add     r4, r4, pc      // r4 = dyld_mh
-       str     r4, [sp, #0]
-       
-       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_
+L3:    add     r4, r4, pc      
+       str     r4, [sp, #0]    // [sp] = dyld_mh
+       add     r4, sp, #12
+       str     r4, [sp, #4]    // [sp+4] = &startGlue
        
-       // clean up stack and jump to result
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_Pm
+       ldr     r5, [sp, #12]
+       cmp     r5, #0
+       bne     Lnew
+       
+       // traditional case, clean up stack and jump to result
        add     sp, r8, #4      // remove the mach_header argument.
        bx      r0              // jump to the program's entry point
 
+       // LC_MAIN case, set up stack for call to main()
+Lnew:  mov     lr, r5              // simulate return address into _start in libdyld
+       mov     r5, r0              // save address of main() for later use
+       ldr     r0, [r8, #4]        // main param1 = argc
+       add     r1, r8, #8          // main param2 = argv
+       add     r2, r1, r0, lsl #2  
+       add     r2, r2, #4          // main param3 = &env[0]
+       mov     r3, r2
+Lapple:        ldr     r4, [r3]
+       add     r3, #4
+       cmp     r4, #0
+       bne     Lapple              // main param4 = apple
+       bx      r5
 
        .align 2
 L__dyld_start_picbase_ptr:
@@ -380,7 +363,7 @@ L_end:
        .align 2
        .globl  _dyld_fatal_error
 _dyld_fatal_error:
-#if __ppc__ || __ppc64__ || __arm__
+#if __arm__
     trap
     nop
 #elif __x86_64__ || __i386__
index 9db993f5f5c33bc3ce7ea6e74f8fa6dd27a0dc48..8132b2ce07bca95c22890cef8c2bae7a423baaa2 100644 (file)
 
 int dummy_dyld_symbol = 1;
 
-#include <stdlib.h>
-
-// The following API's are deprecated.
-// In Mac OS X 10.4 we only do a minimal implementation of these API's 
-// to keep from breaking existing clients (Omni and MS Crash Reporters).
-//
-// This minmal implementation only allows inspection of one process and
-// only reveals the current images in that process (no notification of
-// later image changes). It assumes both processes use the same dyld
-// and dyld has not slid in either process.
-//
-#if __ppc__
-
-#include "mach-o/dyld_debug.h"
-#include "mach-o/dyld_gdb.h"
-#include "mach-o/dyld_priv.h"
-
-// global state set up by _dyld_debug_subscribe_to_events() and accessed by _dyld_debug_module_name()
-static const struct dyld_image_info*   sImages = NULL;
-static uint32_t                                                        sImagesCount = 0;
-static task_port_t                                             sImagesTaskPort = 0;
-
-
-// reads an address range out of another process
-// returns a malloc'ed block that caller should free
-static void* xprocess_read(task_port_t target_task, const void* address, size_t len)
-{
-       void* result = NULL;
-       mach_vm_address_t page_address = (uint32_t)address & (-4096);
-       mach_vm_address_t  last_page_address = ((uint32_t)address + len + 4095) & (-4096);
-       mach_vm_size_t page_size = last_page_address - page_address;
-       uint8_t* local_start;
-       uint32_t local_len;
-       kern_return_t r = vm_read(
-               target_task,
-               page_address,
-               page_size,
-               (vm_offset_t*)&local_start,
-               &local_len);
-       if ( r == KERN_SUCCESS ) {
-               result = malloc(len);
-               if ( result != NULL ) 
-                       memcpy(result, &local_start[(uint32_t)address - page_address], len);
-               vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_len);
-       }
-       return result;
-}
-
-// reads a c-string out of another process.  The returned string should be vm_deallocated.
-// All strings must be less than 1 to 2 pages long
-static const char* xprocess_read_string(task_port_t target_task, const void* address)
-{
-       char* result = NULL;
-       mach_vm_address_t page_address = (uint32_t)address & (-4096);
-       mach_vm_size_t page_size = 0x2000;      // always read two pages
-       uint8_t* local_start;
-       uint32_t local_len;
-       kern_return_t r = vm_read(
-               target_task,
-               page_address,
-               page_size,
-               (vm_offset_t*)&local_start,
-               &local_len);
-       if ( r == KERN_SUCCESS ) {
-               const char* str = (char*)&local_start[(uint32_t)address - page_address];
-               return str;
-       }
-       return result;
-}
-
-
-// SPI into dyld to get address of _dyld_get_all_image_infos data structure
-static const struct dyld_all_image_infos* dyld_get_all_image_infos()
-{
-    static const struct dyld_all_image_infos* (*p)() = NULL;
-
-       if ( p == NULL )
-           _dyld_func_lookup("__dyld_get_all_image_infos", (void**)&p);
-       
-       if ( p != NULL )
-               return p();
-       else
-               return NULL;
-}
-
-
-
-/*
- * _dyld_debug_module_name() is passed a dyld_debug_module struct and
- * sets image_name and module_name as well as the nameCnts.  If the module
- * does not refer to a valid module DYLD_INVALID_ARGUMENTS is returned.
- */
-enum dyld_debug_return
-_dyld_debug_module_name(
-task_port_t target_task,
-unsigned long send_timeout,
-unsigned long rcv_timeout,
-boolean_t inconsistent_data_ok,
-struct dyld_debug_module module,
-char **image_name,
-unsigned long *image_nameCnt,
-char **module_name,
-unsigned long *module_nameCnt)
-{
-       // examine sImage* info set up by _dyld_debug_subscribe_to_events()
-       if ( sImagesTaskPort == target_task ) {
-               unsigned int i;
-               for (i=0; i < sImagesCount; ++i) {
-                       if ( module.header == sImages[i].imageLoadAddress ) {
-                               // copy requested string
-                               const char* path = xprocess_read_string(sImagesTaskPort, sImages[i].imageFilePath);
-                               if ( path != NULL ) {
-                                       *image_name = (char*)path;
-                                       *image_nameCnt = strlen(path);
-                                       *module_name = NULL;
-                                       *module_nameCnt = 0;
-                                       return DYLD_SUCCESS;
-                               }
-                       }
-               }       
-       }
-
-       // not supported
-       return DYLD_INVALID_ARGUMENTS;
-}
-
-
-/*
- * set_dyld_debug_error_func() is called to register a function to be called
- * when error occurs in the dyld debug API's.
- */
-void
-_dyld_debug_set_error_func(
-void (*func)(struct dyld_debug_error_data *e))
-{
-       // do nothing
-}
-
-
-
-// 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;
-               const struct segment_command *sgp = 
-                       (const struct segment_command *)((char*)mh + sizeof(mh));
-
-               for (i = 0; i < mh->ncmds; i++){
-                       if (sgp->cmd == LC_SEGMENT) {
-                               if (sgp->fileoff == 0  &&  sgp->filesize != 0) {
-                                       result = (uintptr_t)mh - (uintptr_t)sgp->vmaddr;
-                                       break;
-                               }
-                       }
-                       sgp = (const struct segment_command *)((char *)sgp + sgp->cmdsize);
-               }
-               free((void*)mh);
-       }
-       return result;  
-}
-
-
-/*
- * _dyld_debug_subscribe_to_events creates a new thread that is will call the
- * specified dyld_event_routine when dynamic link events occur in the target
- * task.  This uses _dyld_debug_add_event_subscriber() and is just a different
- * interface to get events.
- */
-enum dyld_debug_return
-_dyld_debug_subscribe_to_events(
-task_port_t target_task,
-unsigned long send_timeout,
-unsigned long rcv_timeout,
-boolean_t inconsistent_data_ok,
-void (*dyld_event_routine)(struct dyld_event event))
-{
-       sImages = NULL;
-       sImagesCount = 0;
-       sImagesTaskPort = 0;
-       // get location of dyld_get_all_image_infos in this process
-       // It is possible that dyld slid in one of the processes, in which case this fails
-       const struct dyld_all_image_infos* infoOtherAddressSpace = dyld_get_all_image_infos();
-       if ( infoOtherAddressSpace != NULL ) {
-               const struct dyld_all_image_infos* infos;
-               infos = (const struct dyld_all_image_infos*)xprocess_read(target_task, infoOtherAddressSpace, sizeof(struct dyld_all_image_infos));
-               if ( infos != NULL ) {
-                       // sanity check version
-                       if ( infos->version == 1 ) {
-                               sImages = xprocess_read(target_task, infos->infoArray, infos->infoArrayCount * sizeof(struct dyld_image_info));
-                               if ( sImages != NULL ) {
-                                       int i;
-                                       // save info info into sImage* globals for use by later calls to _dyld_debug_module_name()
-                                       sImagesCount = infos->infoArrayCount;
-                                       sImagesTaskPort = target_task;
-                                       // tell caller about every image
-                                       for (i=0; i < infos->infoArrayCount; ++i) {
-                                               struct dyld_event addEvent;
-                                               bzero(&addEvent, sizeof(struct dyld_event));
-                                               const struct mach_header* mh = sImages[i].imageLoadAddress;
-                                               addEvent.type = DYLD_IMAGE_ADDED;
-                                               addEvent.arg[0].header           = (struct mach_header*)mh;
-                                               addEvent.arg[0].vmaddr_slide = slideForHeader(target_task, mh);
-                                               addEvent.arg[0].module_index = 0;
-                                               (*dyld_event_routine)(addEvent);
-                                       }
-                               }
-                       }
-                       // we free the dyld_all_image_infos struct, but not the array we copied
-                       // The array is left in sImage* for use by later calls to _dyld_debug_module_name()
-                       free((void*)infos);
-               }
-       }
-       
-       // tell client event handler no more images
-       struct dyld_event event;
-       event.type = DYLD_PAST_EVENTS_END;
-       (*dyld_event_routine)(event);
-
-       return DYLD_SUCCESS;
-}
-
-#endif
index 9f65555d059b406708411b6756ece73421e4aba7..9ccc656f5e6934277db350a1f0fc5ce1f742d3eb 100644 (file)
@@ -25,6 +25,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 #include <time.h>
 #include <unistd.h>
 #include <stdarg.h>
@@ -240,10 +241,8 @@ char* mach_error_type(mach_error_t err)
 
 // _pthread_reap_thread calls fprintf(stderr). 
 // We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL
-#if !__ppc__
 FILE* __stderrp = NULL;
 FILE* __stdoutp = NULL;
-#endif
 
 // work with c++abi.a
 void (*__cxa_terminate_handler)() = _ZSt9terminatev;
@@ -261,3 +260,20 @@ void __cxa_bad_typeid()
 {
        _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
 }
+
+// to work with libc++
+void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv()
+{
+       _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()");
+}
+
+// libc.a sometimes missing memset
+#undef memset
+void* memset(void* b, int c, size_t len)
+{
+       uint8_t* p = (uint8_t*)b;
+       for(size_t i=len; i > 0; --i)
+               *p++ = c;
+       return b;
+}
+
diff --git a/src/start_glue.s b/src/start_glue.s
new file mode 100644 (file)
index 0000000..4ccfd39
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifdef __i386__
+
+    .align 2
+    .globl _start
+    .private_extern _start
+start:
+       nop             # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+       movl    %eax,(%esp)         # pass result from main() to exit() 
+       call    _exit
+       hlt
+
+#endif /* __i386__ */
+
+
+#if __x86_64__
+
+    .align 2
+    .globl _start
+    .private_extern _start
+start:
+       nop             # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+       movl    %eax,%edi           # pass result from main() to exit() 
+       call    _exit
+       hlt
+
+#endif
+
+
+#if __arm__
+    .align 2
+    .globl _start
+    .private_extern _start
+start:
+       nop                                     // <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+       bl      _exit                   // result in r0 already in param reg r0
+       trap
+#endif /* __arm__ */
+
index aec491f6f4486a4c8aad2e27afed330ce1871689..843347563f632caab32fab64675297c08ad3ac9a 100644 (file)
@@ -180,71 +180,6 @@ _stub_binding_helper_interface:
 #endif
 
 
-#if __ppc__ || __ppc64__
-#include <architecture/ppc/mode_independent_asm.h>
-/*
- * This is the interface for the stub_binding_helper for the ppc:
- * The caller has placed in r11 the address of the a lazy pointer to be filled
- * in with the value for the defined symbol and placed in r12 the address of
- * the the mach header this pointer comes from.
- *
- * r11 address of lazy pointer
- * r12 address of mach header
- */
-#define LRSAVE         MODE_CHOICE(8,16)
-#define STACK_SIZE     MODE_CHOICE(144,288)
-#define R3SAVE          MODE_CHOICE(56,112)
-#define R4SAVE          MODE_CHOICE(60,120)
-#define R5SAVE          MODE_CHOICE(64,128)
-#define R6SAVE          MODE_CHOICE(68,136)
-#define R7SAVE          MODE_CHOICE(72,144)
-#define R8SAVE          MODE_CHOICE(76,152)
-#define R9SAVE          MODE_CHOICE(80,160)
-#define R10SAVE         MODE_CHOICE(84,168)
-
-  
-       .text
-       .align 2
-       .globl _stub_binding_helper_interface
-_stub_binding_helper_interface:
-       mflr    r0                  ; get link register value
-       stg     r0,LRSAVE(r1)       ; save link register value in the linkage area
-       stgu    r1,-STACK_SIZE(r1)  ; save stack pointer and update it
-
-       stg     r3,R3SAVE(r1)   ; save all registers that could contain
-       stg     r4,R4SAVE(r1)   ;  parameters to the routine that is being
-       stg     r5,R5SAVE(r1)   ;  bound.
-       stg     r6,R6SAVE(r1)
-       stg     r7,R7SAVE(r1)
-       stg     r8,R8SAVE(r1)
-       stg     r9,R9SAVE(r1)
-       stg     r10,R10SAVE(r1)
-
-       mr      r3,r12          ; move address of mach header to 1st parameter
-       mr      r4,r11          ; move address of lazy pointer to 2nd parameter
-       ; call dyld::bindLazySymbol(mh, lazy_symbol_pointer_address)
-       bl      __ZN4dyld14bindLazySymbolEPK11mach_headerPm
-       mr      r12,r3          ; move the symbol`s address into r12
-       mtctr   r12             ; move the symbol`s address into count register
-
-       lg      r0,STACK_SIZE+LRSAVE(r1)        ; get old link register value
-
-       lg      r3,R3SAVE(r1)   ; restore all registers that could contain
-       lg      r4,R4SAVE(r1)   ;  parameters to the routine that was bound.
-       lg      r5,R5SAVE(r1)
-       lg      r6,R6SAVE(r1)
-       lg      r7,R7SAVE(r1)
-       lg      r8,R8SAVE(r1)
-       lg      r9,R9SAVE(r1)
-       lg      r10,R10SAVE(r1)
-
-       addi    r1,r1,STACK_SIZE; restore old stack pointer
-       mtlr    r0              ; restore link register
-
-       bctr                    ; jump to the symbol`s address that was bound
-
-#endif /* __ppc__ */
-
 #if __arm__
 /*
  * This is the interface for the stub_binding_helper for ARM:
index 21415cd18a812c65dd1b72c2f5eddb26af34cec0..d6d19fcfd59c5a978b18bb0365083e7b6b3e5bdd 100755 (executable)
@@ -17,9 +17,9 @@ echo "#!/bin/sh" > /var/root/testing/run-all-tests
 chmod +x /var/root/testing/run-all-tests
 
 # do every combination of OS version and architectures
-for os in "4.3" "3.0" 
+for os in "6.0" "3.0" 
 do
-       for arch in armv6 thumb armv7 thumb2
+       for arch in armv7 armv6 thumb
        do
                # make copy of tests
                cp -r ${TEST_CASE_DIR}/../../unit-tests  /var/root/testing/unit-tests-${arch}-${os}
index 461ebb0f2602c95d504660588e6c1e2e4ccd703e..ba256c883b0b31727dc890e0800dacb5d56f64b2 100644 (file)
@@ -6,28 +6,29 @@ SHELL = /bin/sh
 OS_NAME ?= MacOSX
 ifeq "$(OS_NAME)" "iPhoneOS"
        OS_VERSION ?= 3.1
-       ifeq "$(OS_VERSION)" "4.3"
-               OS_BAROLO_FEATURES = 1
+       ifeq "$(findstring -$(OS_VERSION)-,-3.0-3.1-3.2-4.0-4.1-4.2-4.3-)" ""
+               OS_LION_FEATURES = 1
        endif
-       ARCH ?= armv6
-       VALID_ARCHS ?= armv6
+       ARCH ?= armv7
+       VALID_ARCHS ?= armv7
 else
        OS_VERSION ?= 10.7
-       ifeq "$(OS_VERSION)" "10.7"
-               OS_BAROLO_FEATURES = 1
+       ifeq "$(findstring -$(OS_VERSION)-,-10.4-10.5-10.6-)" ""
+               OS_LION_FEATURES = 1
        endif
-       ARCH ?= $(shell arch)
+       ARCH ?= x86_64
        VALID_ARCHS ?= "i386 x86_64"
 endif
 
+IOSROOT        = 
+
 ifeq "$(OS_NAME)" "iPhoneOS"
-       CC                      = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.Internal.sdk
-       CXX                     = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.Internal.sdk
-#      CC                      = gcc-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION)
-#      CXX                     = g++-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION)
+       IOSROOT         = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.Internal.sdk
+       CC                      = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cc -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
+       CXX                     = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/c++ -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
 else
-       CC                      = gcc-4.2 -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
-       CXX                     = g++-4.2 -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+       CC                      = cc -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+       CXX                     = c++ -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
 endif
 
 CCFLAGS                = -Wall -std=c99
index 91659ba8c6b82369bc42497441a1eefd17036ff9..ceb2106175320b8adf5a54df3f1bd86d91b23c8f 100755 (executable)
@@ -8,7 +8,7 @@ CRSTATE=`defaults read com.apple.CrashReporter DialogType`
 defaults write com.apple.CrashReporter DialogType basic
 
 # run test targeting different OS versions
-for OSVERSION in 10.7 10.6 10.5 10.4
+for OSVERSION in 10.8 10.7 10.6 10.5 10.4
 do 
        echo ""
        echo " * * * Running all unit tests i386 built for $OSVERSION * * *"
index a903b04b7af5f87d08bf09d77ae989c26cd38043..224d93e8527e7a64f070ef5878d9d8b5daea06bd 100644 (file)
@@ -34,12 +34,14 @@ extern int foo();
 
 int main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int expectedResult = atoi(argv[1]);
        int actualResult = foo();
        //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
        if ( actualResult != expectedResult )
                FAIL("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
        else
+#endif
                PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
                
        return EXIT_SUCCESS;
index 36bf14e786f65b382f80283425ffaeccb7bf68dc..5c0374b60e36fa06f432aa008b7cf3d15c85387e 100644 (file)
@@ -25,9 +25,21 @@ include ${TESTROOT}/include/common.makefile
 
 PWD = $(shell pwd)
 
-all-check: all check
+ifeq "$(OS_NAME)" "iPhoneOS"
+       CHECK = check-ios
+else
+       CHECK = check-macosx
+endif
 
-check:
+
+all-check: all $(CHECK)
+
+check: $(CHECK)
+
+check-ios:
+       ./main 10
+
+check-macosx:
        ./main 10
        export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt11" && ./main 11
        export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt9" && ./main 10
index a903b04b7af5f87d08bf09d77ae989c26cd38043..2815ba1fc4a15c334671077aec18bb5957a04351 100644 (file)
@@ -34,13 +34,15 @@ extern int foo();
 
 int main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int expectedResult = atoi(argv[1]);
        int actualResult = foo();
        //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
        if ( actualResult != expectedResult )
-               FAIL("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+               FAIL("DYLD_VERSIONED_FRAMEWORK_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
        else
-               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+#endif
+               PASS("DYLD_VERSIONED_FRAMEWORK_PATH-basic");
                
        return EXIT_SUCCESS;
 }
index 2be1439c6a46c8a120534bb694682c121dae936c..788e74af44df5e610f57dc2a0360d32d94fb00e7 100644 (file)
@@ -25,9 +25,20 @@ include ${TESTROOT}/include/common.makefile
 
 PWD = $(shell pwd)
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       CHECK = check-ios
+else
+       CHECK = check-macosx
+endif
+
 all-check: all check
 
-check:
+check: $(CHECK)
+
+check-ios:
+       ./main 10
+
+check-macosx:
        ./main 10
        export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt11" && ./main 11
        export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt9" && ./main 10
index a903b04b7af5f87d08bf09d77ae989c26cd38043..224d93e8527e7a64f070ef5878d9d8b5daea06bd 100644 (file)
@@ -34,12 +34,14 @@ extern int foo();
 
 int main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int expectedResult = atoi(argv[1]);
        int actualResult = foo();
        //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
        if ( actualResult != expectedResult )
                FAIL("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
        else
+#endif
                PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
                
        return EXIT_SUCCESS;
index a903b04b7af5f87d08bf09d77ae989c26cd38043..224d93e8527e7a64f070ef5878d9d8b5daea06bd 100644 (file)
@@ -34,12 +34,14 @@ extern int foo();
 
 int main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int expectedResult = atoi(argv[1]);
        int actualResult = foo();
        //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
        if ( actualResult != expectedResult )
                FAIL("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
        else
+#endif
                PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
                
        return EXIT_SUCCESS;
index a903b04b7af5f87d08bf09d77ae989c26cd38043..224d93e8527e7a64f070ef5878d9d8b5daea06bd 100644 (file)
@@ -34,12 +34,14 @@ extern int foo();
 
 int main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int expectedResult = atoi(argv[1]);
        int actualResult = foo();
        //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
        if ( actualResult != expectedResult )
                FAIL("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
        else
+#endif
                PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
                
        return EXIT_SUCCESS;
index 006adaa4e6fd94610d157bb4317dd643028dae6f..72b371028e2a70052d0aabe43d5286945af6275d 100644 (file)
@@ -38,6 +38,13 @@ const char* pc   = &c;
 const char* pd_2 = &d - 2;
 const char* pb2  = &b + 2;
 
+const char* pd_1234567890 = &d - 1234567890;
+const char* pd1234567890  = &d + 1234567890;
+
+#if __LP64__
+const char* pd_12345678901234 = &d - 12345678901234;
+const char* pd12345678901234  = &d + 12345678901234;
+#endif
 
 int main()
 {
@@ -56,6 +63,28 @@ int main()
                return 0;
        }
        
+       if (pd_1234567890[1234567890] != 13 ) {
+               FAIL("addend: pd_1234567890[1234567890] != 13");
+               return 0;
+       }
+       
+       if (pd1234567890[-1234567890] != 13 ) {
+               FAIL("addend: pd1234567890[-1234567890] != 13");
+               return 0;
+       }
+       
+#if __LP64__
+       if (pd_12345678901234[12345678901234] != 13 ) {
+               FAIL("addend: pd_12345678901234[12345678901234] != 13");
+               return 0;
+       }
+       
+       if (pd12345678901234[-12345678901234] != 13 ) {
+               FAIL("addend: pd12345678901234[-12345678901234] != 13");
+               return 0;
+       }
+#endif 
+       
        PASS("addend");
        return 0;
 }
index 687eea699d8a9073c8862adc9cce9e5e576322a7..e87cda5f81b5ac85327d8ef2ea883ba9d3b005bd 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2011 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -23,7 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-FATFLAGS = `lipo -detailed_info /usr/lib/libSystem.B.dylib | grep architecture | sed -e 's/architecture/-arch/'`
+FATFLAGS = $(shell lipo -detailed_info $(IOSROOT)/usr/lib/libSystem.B.dylib | grep architecture | sed -e 's/architecture/-arch/')
 
 all-check: all check
 
@@ -36,7 +36,9 @@ main : main.c
        ${CC} ${CCFLAGS}  -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
 
 test.bundle : bundle.c
-       gcc ${FATFLAGS} -bundle -o test.bundle bundle.c
+       echo ${IOSROOT}
+       echo $(IOSROOT)
+       ${CC} ${FATFLAGS} -bundle -o test.bundle bundle.c
 
 clean:
        ${RM} ${RMFLAGS} *~ main test.bundle
index 938ea758f3d4d96c739419d51519ca5e363ebf27..56690a786c53faa33a1f158f8d5feffb444b2317 100644 (file)
@@ -28,5 +28,5 @@ static int mydata[10];
 
 bool checkdata()
 {
-       return ( mydata[10] == 0 );
+       return ( mydata[9] == 0 );
 }
index 78e43d593663fc35b4fde857c2818ec099639454..bc160be597304c3f323ed2db1376709f49910975 100644 (file)
@@ -23,6 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
 #
 # verify that apple[0] parameter is correct by comparing to argv[1]
 #
@@ -34,7 +37,7 @@ check:
        ./main.stripped ./main.stripped
        `pwd`/main `pwd`/main
        `pwd`/main.stripped `pwd`/main.stripped
-       export DYLD_LIBRARY_PATH=. && export DYLD_FRAMEWORK_PATH=. && ./main-setuid ./main-setuid
+       export DYLD_LIBRARY_PATH=. && export DYLD_FRAMEWORK_PATH=. && ./main-setuid ./main-setuid 2>/dev/null
 
 all: main  main.stripped main-setuid
 
index 0d888ad0dda43e3a636d75a6398c8998f326c9d2..8a56fd87a9d27046301920e2ae031ae53d7308f7 100644 (file)
@@ -71,9 +71,9 @@ 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]);
+               PASS("crt-apple %s", apple[0]);
        else
-               FAIL("crt-apple %s", argv[0]);
+               FAIL("crt-apple %s", apple[0]);
                
        return EXIT_SUCCESS;
 }
index ee12f105146b48667b67772d81ed3b223d8e75bf..7bb8ddc395aa144319b49846c0c06f3bdb82a56c 100644 (file)
@@ -37,7 +37,7 @@ check:
 all: main
 
 main: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main mystart.s main.c -e _mystart
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main mystart.s main.c -e _mystart -Wl,-no_new_main
 
 
 clean:
index a95e0b511824da84125229e77e559f1634e8419f..c507706d66d05875fb77e7c9dcf213b417799705 100644 (file)
@@ -6,6 +6,7 @@
 
 
        .text
+       .align 2
        .globl _mystart
 _mystart:
 #if __i386__ 
diff --git a/unit-tests/test-cases/dlopen_preflight-cycle/Makefile b/unit-tests/test-cases/dlopen_preflight-cycle/Makefile
new file mode 100644 (file)
index 0000000..2123b40
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib bar.c 
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbaz.dylib baz.c -Wl,-upward_library,libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib bar.c  libbaz.dylib
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.c libbar.dylib  
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libbaz.dylib libbar.dylib libfoo.dylib 
+
diff --git a/unit-tests/test-cases/dlopen_preflight-cycle/bar.c b/unit-tests/test-cases/dlopen_preflight-cycle/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-cycle/baz.c b/unit-tests/test-cases/dlopen_preflight-cycle/baz.c
new file mode 100644 (file)
index 0000000..256a0e3
--- /dev/null
@@ -0,0 +1 @@
+void baz() {}
diff --git a/unit-tests/test-cases/dlopen_preflight-cycle/foo.c b/unit-tests/test-cases/dlopen_preflight-cycle/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-cycle/main.c b/unit-tests/test-cases/dlopen_preflight-cycle/main.c
new file mode 100644 (file)
index 0000000..af5caec
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int main(int argc, const char* argv[])
+{
+       if ( ! dlopen_preflight("libfoo.dylib") ) {
+               FAIL("dlopen_preflight-cycle libfoo.dylib should not be loadable");
+               return EXIT_SUCCESS;
+       }
+
+       void* handle = dlopen("libbar.dylib", RTLD_NOLOAD);
+       if ( handle != NULL ) {
+               FAIL("dlopen_preflight-cycle libbar.dylib was left loaded by dlopen_preflight()");
+               return EXIT_SUCCESS;
+       }
+       
+       handle = dlopen("libbaz.dylib", RTLD_NOLOAD);
+       if ( handle != NULL ) {
+               FAIL("dlopen_preflight-cycle libbaz.dylib was left loaded by dlopen_preflight()");
+               return EXIT_SUCCESS;
+       }
+
+       handle = dlopen("libfoo.dylib", RTLD_NOLOAD);
+       if ( handle != NULL ) {
+               FAIL("dlopen_preflight-cycle libfoo.dylib was left loaded by dlopen_preflight()");
+               return EXIT_SUCCESS;
+       }
+
+       PASS("dlopen_preflight-cycle");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dyld-slide/Makefile b/unit-tests/test-cases/dyld-slide/Makefile
deleted file mode 100644 (file)
index aa3debf..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
-#
-# @APPLE_LICENSE_HEADER_START@
-# 
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
-# 
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
-# limitations under the License.
-# 
-# @APPLE_LICENSE_HEADER_END@
-##
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-STACK_BASE = 0x8fe01000
-STACK_SIZE = 0x00100000
-
-ifeq "armv6" "$(ARCH)"
-       STACK_BASE = 0x2fe01000
-       STACK_SIZE = 0x00100000
-endif
-ifeq "armv7" "$(ARCH)"
-       STACK_BASE = 0x2fe01000
-       STACK_SIZE = 0x00100000
-endif
-ifeq "ppc64" "$(ARCH)"
-       STACK_BASE = 0x7fff5ff00000
-       STACK_SIZE = 0x00400000
-endif
-ifeq "x86_64" "$(ARCH)"
-       STACK_BASE = 0x7fff5ff00000
-       STACK_SIZE = 0x00400000
-endif
-
-
-
-all-check: all check
-
-check:
-       ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main
-
-all:
-       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,${STACK_SIZE}
-
-clean:
-       ${RM} ${RMFLAGS} main
diff --git a/unit-tests/test-cases/dyld-slide/main.c b/unit-tests/test-cases/dyld-slide/main.c
deleted file mode 100644 (file)
index a689f63..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-#include <stdlib.h> // EXIT_SUCCESS
-#include <dlfcn.h>
-#include <mach-o/dyld_priv.h>
-
-#include "test.h"
-
-//
-// This builds an executable that is just big enough to force dyld to slide a bit
-//
-#if __arm__
-       #define ARRAY_SIZE  66582528
-#else
-       #define ARRAY_SIZE 335400000
-#endif
-
-//int bigarray1[ARRAY_SIZE];
-
-int
-main()
-{
-       // call a dyld function that will execute lots of code and bus error dyld was not slid
-       dlsym(RTLD_DEFAULT, "foobar");
-
-       return EXIT_SUCCESS;
-}
-
-
index f0ea7791a905a2818cc4dec56bcf879b1801dc16..351769ade4e45506648ee73f69b123e61ffc838a 100644 (file)
@@ -31,6 +31,8 @@
 ///  main links directly against one libfoo.dylib and indirectly through libbar.dylib with the other.
 ///
 
+extern int foo();
+extern int bar();
 
 int main(int argc, const char* argv[])
 {
diff --git a/unit-tests/test-cases/image-state-deny-all_image_infos/Makefile b/unit-tests/test-cases/image-state-deny-all_image_infos/Makefile
new file mode 100644 (file)
index 0000000..56dd654
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main bar.bundle
+
+main: main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c 
+
+bar.bundle: bar.c
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o bar.bundle bar.c  
+
+clean:
+       ${RM} ${RMFLAGS} *~ main bar.bundle
+
diff --git a/unit-tests/test-cases/image-state-deny-all_image_infos/bar.c b/unit-tests/test-cases/image-state-deny-all_image_infos/bar.c
new file mode 100644 (file)
index 0000000..e425999
--- /dev/null
@@ -0,0 +1 @@
+void bar() {}
diff --git a/unit-tests/test-cases/image-state-deny-all_image_infos/main.c b/unit-tests/test-cases/image-state-deny-all_image_infos/main.c
new file mode 100644 (file)
index 0000000..ed4b56c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <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_images.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* 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 void load(const char* name)
+{
+       void* handle = dlopen(name, RTLD_LAZY);
+       if ( handle != NULL ) {
+               FAIL("image-state-deny-all_image_infos: dlopen(%s) should have failed", name);
+               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_mapped, false, singleMappedHandler);
+       
+    const struct dyld_all_image_infos* infos = _dyld_get_all_image_infos();
+    const uint32_t initialCount = infos->infoArrayCount;
+    
+       load("bar.bundle");
+
+    if ( infos->infoArrayCount != initialCount ){
+               FAIL("image-state-deny-all_image_infos: infoArrayCount should not have changed");
+               exit(0);
+       }
+
+    //for (int i=0; i < infos->infoArrayCount; ++i)
+    //    printf("mh=%p, path=%s\n", infos->infoArray[i].imageLoadAddress, infos->infoArray[i].imageFilePath); 
+       
+       PASS("image-state-deny-all_image_infos");
+               
+       return EXIT_SUCCESS;
+}
index 28b4c8e65e192fbfd52272376301090425fa8fa0..204744edc04fadd177c9644e3aa818454fa398a3 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <dlfcn.h>
 
 #include "test.h"
 
index aa3576533c261447cb10520fa690a80052877deb..42f9e422aa7897314937b792562b24ab2d56bfe7 100644 (file)
@@ -26,7 +26,7 @@ include ${TESTROOT}/include/common.makefile
 all-check: all check
 
 check:
-       ./main 
+       ${PASS_IFF_FAILURE} ./main 
        
 all:
        ${CC} ${CCFLAGS} -I${TESTROOT}/include bar.c -dynamiclib -o libbar.dylib
index f466342a153d76b0d9880dcac03f02123f2fee5a..bd4a512b0aed4f7fdb74b68137e145101125c90a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -30,13 +30,9 @@ extern int bar;
 int
 main()
 {
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
        if ( bar == 1 )
                FAIL("initializer-bounds-check, out of bounds initializer called");
        else
                PASS("initializer-bounds-check");
-#else
-               PASS("initializer-bounds-check");
-#endif
   return EXIT_SUCCESS;
 }
index b270917c5e946eb36af4dd643dde5050a180f948..c06cad5f7f5324eaa8e2c13fcfcc9668f1cf16c7 100644 (file)
@@ -23,6 +23,8 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+SHELL = bash # use bash shell so we can redirect just stderr
+
 PWD = `pwd`
 
 ifeq "$(OS_NAME)" "iPhoneOS"
@@ -34,7 +36,7 @@ endif
 all-check: all check
 
 check:
-       ${RUN_AS_USER} $(PWD)/main-with-env
+       ${RUN_AS_USER} $(PWD)/main-with-env insert-libraries-with-suid 2>/dev/null
 
 all: main
 
index 192b3b6dc4f912500549a88240ff121cf79f1a76..93ef8980e8ec34ad752531f6e3dcd66593113a53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <string.h>
 #include <dlfcn.h>
+#include <stdbool.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+extern bool allocationSeen(void* p);
+typedef bool (*seenProc)(void*);
 
 int main()
 {
-       const char* x = strdup("123");
-  
-       if ( (strcmp(&x[-16], "hello") == 0) )
+       void* x = strdup("123");
+       
+       seenProc seen = (seenProc)dlsym(RTLD_DEFAULT, "allocationSeen");
+       
+       if ( (seen != NULL) && (*seen)(x) )
                PASS("interpose-basic-shared-cache");
        else
                FAIL("interpose-basic-shared-cache");
index 9afe7f15bd865d2a29c99d170bf6ddf83dd22edb..bca0938823d2b1e8b85e66a79cd04f7ea35e9092 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  */
 
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
+#include <stdbool.h>
 #include <mach-o/dyld-interposing.h>
+#include <malloc/malloc.h>
 
-// return blocks that have preceeding 16-bytes filled with "hello"
+static void* seenAllocations[128];
+static int seenAllocationIndex = 0;
+
+// record each malloc result in a ring buffer
 void* my_malloc(size_t size)
 {
-       char* x = malloc(size+16);
-       strcpy(x, "hello");
-       return &x[16];
+       char* x = malloc(size);
+       seenAllocations[seenAllocationIndex++] = x;
+       seenAllocationIndex = (seenAllocationIndex & 127); //wrap around
+       return x;
 }
 
 DYLD_INTERPOSE(my_malloc, malloc)
+
+bool allocationSeen(void* p)
+{
+       for(int i=0; i < 127; ++i) {
+               if ( seenAllocations[i] == p )
+                       return true;
+       }
+       return false;
+}
+
+
+
diff --git a/unit-tests/test-cases/loader_path-symlink/Makefile b/unit-tests/test-cases/loader_path-symlink/Makefile
new file mode 100644 (file)
index 0000000..7fab8fc
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+#
+# <rdar://problem/10879179> a dylib is found via symlink and must find another dylib relative to the symlink
+#
+
+all-check: all check
+
+check:
+       ./bin/main
+
+all: 
+       mkdir -p Frameworks/Foo.framework/Versions/A
+       mkdir -p Frameworks/Bar.framework/Versions/A
+       ${CC} bar.c -dynamiclib -o Frameworks/Bar.framework/Versions/A/Bar -install_name @loader_path/../Bar.framework/Bar
+       (cd Frameworks/Foo.framework; ln -fs Versions/A/Foo)
+       (cd Frameworks/Bar.framework; ln -fs Versions/A/Bar)
+       ${CC} foo.c -dynamiclib -o Frameworks/Foo.framework/Versions/A/Foo -install_name @loader_path/../Frameworks/Foo.framework/Foo Frameworks/Bar.framework/Versions/A/Bar
+       mkdir -p bin
+       ${CC} -I${TESTROOT}/include main.c -o bin/main Frameworks/Foo.framework/Versions/A/Foo
+       
+
+clean:
+       ${RM} -rf *~  Frameworks bin
diff --git a/unit-tests/test-cases/loader_path-symlink/bar.c b/unit-tests/test-cases/loader_path-symlink/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/loader_path-symlink/foo.c b/unit-tests/test-cases/loader_path-symlink/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/loader_path-symlink/main.c b/unit-tests/test-cases/loader_path-symlink/main.c
new file mode 100644 (file)
index 0000000..4c91a7c
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       PASS("loader_path-symlink");
+       return EXIT_SUCCESS;
+}
index a83adcd1e9f6bdb4f7f4fac6dfdc901a25c9f8af..31d75d6b20e4c3809f4ab1e85793c2f35331bf9b 100644 (file)
@@ -29,6 +29,10 @@ ifeq "x86_64" "$(ARCH)"
        EXTRA_OPTIONS = 
 endif
 
+ifeq "iPhoneOS" "$(OS_NAME)"
+       EXTRA_OPTIONS = 
+endif
+
 
 # run a PIE four times and verify its load address was different every time
 
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/Makefile b/unit-tests/test-cases/re-export-symbol-dylib/Makefile
new file mode 100644 (file)
index 0000000..9465192
--- /dev/null
@@ -0,0 +1,59 @@
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+#
+# Test that fine grain re-exports works
+#
+
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
+
+all: all_$(OS_LION_FEATURES)
+
+check: check_$(OS_LION_FEATURES)
+
+check_1:
+       ./main
+
+all_1:
+       # build frob
+       ${CC} ${CCFLAGS} -dynamiclib frob.c -o libfrob.dylib
+       # build baz to re-export all of frob
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib -exported_symbols_list baz.exp libfrob.dylib
+       # build bar to re-export all of baz
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib
+       # build foo to re-export all of bar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list foo.exp  libbar.dylib
+       # buid main
+       ${CC} ${CCFLAGS} main.c -I${TESTROOT}/include libfoo.dylib -o main
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+       
+clean:
+       rm -rf libbar.dylib libfoo.dylib libbaz.dylib libfrob.dylib  main
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/bar.c b/unit-tests/test-cases/re-export-symbol-dylib/bar.c
new file mode 100644 (file)
index 0000000..18d7633
--- /dev/null
@@ -0,0 +1,5 @@
+
+int bar(void)
+{
+       return 2;
+}
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/baz.c b/unit-tests/test-cases/re-export-symbol-dylib/baz.c
new file mode 100644 (file)
index 0000000..cb30818
--- /dev/null
@@ -0,0 +1,5 @@
+int baz() 
+{
+  return 3;
+}
+
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/baz.exp b/unit-tests/test-cases/re-export-symbol-dylib/baz.exp
new file mode 100644 (file)
index 0000000..5fbf7f4
--- /dev/null
@@ -0,0 +1,2 @@
+_baz
+_frob
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/foo.c b/unit-tests/test-cases/re-export-symbol-dylib/foo.c
new file mode 100644 (file)
index 0000000..72b3c29
--- /dev/null
@@ -0,0 +1,4 @@
+int foo(void)
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/foo.exp b/unit-tests/test-cases/re-export-symbol-dylib/foo.exp
new file mode 100644 (file)
index 0000000..aff96a1
--- /dev/null
@@ -0,0 +1,4 @@
+_foo
+_bar
+_baz
+_frob
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/frob.c b/unit-tests/test-cases/re-export-symbol-dylib/frob.c
new file mode 100644 (file)
index 0000000..3df9d3d
--- /dev/null
@@ -0,0 +1,5 @@
+int frob()
+{
+  return 4;
+}
+
diff --git a/unit-tests/test-cases/re-export-symbol-dylib/main.c b/unit-tests/test-cases/re-export-symbol-dylib/main.c
new file mode 100644 (file)
index 0000000..f12dd10
--- /dev/null
@@ -0,0 +1,44 @@
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+extern int foo();
+extern int bar();
+extern int baz();
+extern int frob();
+
+int (*pfoo)() = &foo;
+int (*pbar)() = &bar;
+int (*pbaz)() = &baz;
+int (*pfrob)() = &frob;
+
+
+int main()
+{
+       if ( foo() != 1 )
+               FAIL("re-export-symbol-dylib: foo() returned wrong value");
+       else if ( bar() != 2 )
+               FAIL("re-export-symbol-dylib: bar() returned wrong value");
+       else if ( baz() != 3 )
+               FAIL("re-export-symbol-dylib: baz() returned wrong value");
+       else if ( frob() != 4 )
+               FAIL("re-export-symbol-dylib: frob() returned wrong value");
+    
+       else if ( (*pfoo)() != 1 )
+               FAIL("re-export-symbol-dylib: (*pfoo)() returned wrong value");
+       else if ( (*pbar)() != 2 )
+               FAIL("re-export-symbol-dylib: (*pbar)() returned wrong value");
+       else if ( (*pbaz)() != 3 )
+               FAIL("re-export-symbol-dylib: (*pbaz)() returned wrong value");
+       else if ( (*pfrob)() != 4 )
+               FAIL("re-export-symbol-dylib: (*pfrob)() returned wrong value");
+    else 
+        PASS("re-export-symbol-dylib");
+       return 0;
+}
+
index 3be241506771130cf56fc1d96807f4d71f37e797..c02f9124731576ef65bb0da24b08227e99d13fc1 100644 (file)
@@ -29,11 +29,11 @@ include ${TESTROOT}/include/common.makefile
 # Test that fine grain re-exports works
 #
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-all: all_$(OS_BAROLO_FEATURES)
+all: all_$(OS_LION_FEATURES)
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_1:
        ./main1
index fdadfc76c49a7980965cd06ab7bf54729c6987d9..b9420c7bf40e626d34b7b9a77062e156a87ebd6f 100644 (file)
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <unistd.h>
+#include <Availability.h>
 #include <mach-o/getsect.h>
 #include <mach/mach.h> 
 #include <mach/mach_vm.h> 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 
 extern void foo();
 extern int fooData;
@@ -107,4 +109,14 @@ int main()
        return EXIT_SUCCESS;
 }
 
+#else
+
+int main()
+{
+       // iOS does not have modifiable stubs
+       PASS("read-only-stubs");
+       return EXIT_SUCCESS;
+}
+
+#endif
 
index 8aa6bea413796277bf79a76cefeeea50061c6015..a22a543f29bf47221e58db79c6e774c85a73f7e4 100644 (file)
@@ -23,6 +23,8 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+SHELL = bash # use bash shell so we can redirect just stderr
+
 ifeq "$(OS_NAME)" "iPhoneOS"
        RUN_AS_USER = login -f -l mobile
 else
@@ -34,7 +36,7 @@ PWD = `pwd`
 all-check: all check
 
 check:
-       ${RUN_AS_USER} $(PWD)/main-with-env
+       ${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
 
 all: main
 
index d4f0b335ee313a6db8819a80e19fbbe311bdd52c..9857c71564b27a78004d4731ecc72936bc392e00 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <unistd.h>
 #include <mach-o/dyld.h>
 
 #include "test.h"
diff --git a/unit-tests/test-cases/rpath-introspection/Makefile b/unit-tests/test-cases/rpath-introspection/Makefile
new file mode 100644 (file)
index 0000000..ec5d680
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+#
+# Checks that @rpath that expands to have ../ in it will get realpathed and 
+# .. will not be seen when introspecting dylibs
+#
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       mkdir -p hide/hole
+       ${CC} foo.c -dynamiclib -o hide/hole/libfoo.dylib -install_name @rpath/libfoo.dylib 
+       ${CC} -I${TESTROOT}/include main.c -o main hide/hole/libfoo.dylib -Wl,-rpath -Wl,${PWD}/hide/../hide/hole
+
+clean:
+       ${RM} -rf *~  main hide
diff --git a/unit-tests/test-cases/rpath-introspection/foo.c b/unit-tests/test-cases/rpath-introspection/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-introspection/main.c b/unit-tests/test-cases/rpath-introspection/main.c
new file mode 100644 (file)
index 0000000..6eba6da
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       
+       // make sure foo's path does not have .. in it
+       int count = _dyld_image_count();
+       bool found = false;
+       for(int i=0; i < count; ++i) {
+               const char* name = _dyld_get_image_name(i);
+               if ( strstr(name, "libfoo.dylib") == 0 ) {
+                       found = true;
+                       if ( strstr(name, "..") != NULL ) {
+                               FAIL("rpath-introspection: _dyld_get_image_name(%d) returned %s", i, name);
+                               return EXIT_SUCCESS;
+                       }
+               }
+       }
+       if ( !found ) {
+               FAIL("rpath-introspection: _dyld_get_image_name() never returned libfoo.dylib");
+               return EXIT_SUCCESS;
+       }
+       
+       // make sure dladdr path does not have .. in it
+       Dl_info info;
+       if ( dladdr(&foo, &info) == 0 ) {
+               FAIL("rpath-introspection: dladdr() failed");
+               return EXIT_SUCCESS;
+       }
+       if ( strstr(info.dli_fname, "..") != NULL ) {
+               FAIL("rpath-introspection: dladdr() returned path with .. in it");
+               return EXIT_SUCCESS;
+       }
+       
+       PASS("rpath-introspection");
+       return EXIT_SUCCESS;
+}
index 2b1cc256fcb755003d08c0282a5e076ef4747d4f..69b4a598cb6feac4cca88dfdefaad9152d8e7f05 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include <dlfcn.h>
 
 #include "test.h"
 
index 7797d2e4942537162e344183ed735917942d66b6..6356a4a6f83a551e326915b302e9a2b83fc6eb00 100644 (file)
@@ -23,6 +23,8 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+SHELL = bash # use bash shell so we can redirect just stderr
+
 ifeq "$(OS_NAME)" "iPhoneOS"
        RUN_AS_USER = login -f -l mobile
 else
@@ -34,7 +36,7 @@ PWD = `pwd`
 all-check: all check
 
 check:
-       ${RUN_AS_USER} $(PWD)/main-with-env
+       ${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
 
 all: main
 
index cfc8ac03403552059abdca504b9ea375465ca13a..f38f287d9dfefb4c0ea7cd2ed83b8fa47f43ffd1 100644 (file)
@@ -28,11 +28,11 @@ include ${TESTROOT}/include/common.makefile
 ## Basic test of symbol-resolver functions
 ##
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-all: all_$(OS_BAROLO_FEATURES) 
+all: all_$(OS_LION_FEATURES) 
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_:
        ${PASS_IFF} true
diff --git a/unit-tests/test-cases/symbol-resolver-interposed/Makefile b/unit-tests/test-cases/symbol-resolver-interposed/Makefile
new file mode 100644 (file)
index 0000000..2d0c380
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+##
+## Test that resolver based functions can be interposed
+##
+
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
+
+all: all_$(OS_LION_FEATURES) 
+
+check: check_$(OS_LION_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+       export DYLD_INSERT_LIBRARIES=myfoo.interposelib && ./main
+
+all_1:  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+       ${CC} ${CCFLAGS} -dynamiclib myfoo.c libfoo.dylib -o myfoo.interposelib  
+
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib myfoo.interposelib 
+
diff --git a/unit-tests/test-cases/symbol-resolver-interposed/foo.c b/unit-tests/test-cases/symbol-resolver-interposed/foo.c
new file mode 100644 (file)
index 0000000..8e9ff7e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+
+static int which_foo = 0;
+
+void set_foo(int x)
+{
+       which_foo = x;
+}
+
+static int foo_ten()
+{
+       return 10;
+}
+
+static int foo_zero()
+{
+       return 0;
+}
+
+
+// This foo is a "resolver" function that return the actual address of "foo"
+void* foo()
+{
+       __asm__(".symbol_resolver _foo");  // magic until we have compiler support
+       if ( which_foo == 0 )
+               return &foo_zero;
+       else
+               return &foo_ten;
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-interposed/foo.h b/unit-tests/test-cases/symbol-resolver-interposed/foo.h
new file mode 100644 (file)
index 0000000..2c1d57b
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern int foo();
+extern void set_foo(int);
diff --git a/unit-tests/test-cases/symbol-resolver-interposed/main.c b/unit-tests/test-cases/symbol-resolver-interposed/main.c
new file mode 100644 (file)
index 0000000..32c1ccb
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include "foo.h"
+
+int main(int argc, const char* argv[])
+{
+       if ( getenv("DYLD_INSERT_LIBRARIES") == NULL ) {
+               if ( foo() != 0 ) {
+                       FAIL("symbol-resolver-interposed: foo() != 0");
+                       return EXIT_SUCCESS;
+               }
+       }
+       else {
+               if ( foo() != 20 ) {
+                       FAIL("symbol-resolver-interposed: foo() != 20");
+                       return EXIT_SUCCESS;
+               }
+       }
+       
+       PASS("symbol-resolver-interposed");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/symbol-resolver-interposed/myfoo.c b/unit-tests/test-cases/symbol-resolver-interposed/myfoo.c
new file mode 100644 (file)
index 0000000..a85ee6a
--- /dev/null
@@ -0,0 +1,10 @@
+
+#include <mach-o/dyld-interposing.h>
+#include "foo.h"
+
+int myfoo()
+{
+       return 20;
+}
+
+DYLD_INTERPOSE(myfoo, foo)
index 91436718d25e932c78c8ced3645ff065c1346cf3..bf8e689cff37139d2ae2588bab6d7044a52390be 100644 (file)
@@ -28,11 +28,11 @@ include ${TESTROOT}/include/common.makefile
 ## Basic test of symbol-resolver functions
 ##
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-all: all_$(OS_BAROLO_FEATURES) 
+all: all_$(OS_LION_FEATURES) 
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_:
        ${PASS_IFF} true
diff --git a/unit-tests/test-cases/terminator-bounds-check/Makefile b/unit-tests/test-cases/terminator-bounds-check/Makefile
new file mode 100644 (file)
index 0000000..71d7002
--- /dev/null
@@ -0,0 +1,36 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ${PASS_IFF_FAILURE} ./main 
+       
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main 
+
diff --git a/unit-tests/test-cases/terminator-bounds-check/main.c b/unit-tests/test-cases/terminator-bounds-check/main.c
new file mode 100644 (file)
index 0000000..50177bb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern void* terminators[] __asm__("section$start$__DATA$__mod_term_func");
+
+
+__attribute__((destructor))
+void myterm()
+{
+       FAIL("terminator-bounds-check, terminator called");
+       exit(0);
+}
+
+
+
+int
+main()
+{
+       // stomp on terminator routine to point into libSystem (_rand)
+       terminators[0] = &rand;
+       return EXIT_SUCCESS;
+}
index 6a03b28b071808859e5137cc3870d8b07a82074e..b644c3db889f273c06ee9f7f1ca1c583852a03b6 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <unistd.h>
+#include <Availability.h>
 #include <mach-o/getsect.h>
 #include <mach-o/ldsyms.h>
 #include <mach/mach.h> 
@@ -30,6 +31,7 @@
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 
 static vm_prot_t getPermission(void* addr)
 {
@@ -98,4 +100,12 @@ void foo()
        checkStubs(stubAddr);
 }
 
+#else
+
+void foo() 
+{
+       // iOS does not have text relocs
+}
+
+#endif
 
index b4994b0584e77402687f270ea352c7e11fed0097..fc07f175b23fe9416bdd3162d92a3a5d47b01bd0 100644 (file)
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <unistd.h>
+#include <Availability.h>
 #include <mach-o/getsect.h>
 #include <mach/mach.h> 
 #include <mach/mach_vm.h> 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+
 extern void foo();
 
 static vm_prot_t getPermission(void* addr)
@@ -106,4 +109,14 @@ int main()
        return EXIT_SUCCESS;
 }
 
+#else
+
+int main()
+{
+       // iOS does not have text relocs
+       PASS("text-relocs-perm");
+       return EXIT_SUCCESS;
+}
+
+#endif
 
index a024a28f5f3a5f32414de99b299d27502a4fc208..1048e84c8b02bf3b0c06c2cbcf10abb0a11aeb37 100644 (file)
@@ -30,10 +30,12 @@ include ${TESTROOT}/include/common.makefile
 
 
 TEXT_RELOC_FLAGS = -mdynamic-no-pic -read_only_relocs suppress -Wl,-w
+TEXT_STAT_FLAGS = -static
 
-ifeq "ppc64" "$(ARCH)"
-       # ppc64 does not support text relocs
+ifeq "iPhoneOS" "$(OS_NAME)"
+       # iOS does not support text relocs
        TEXT_RELOC_FLAGS = 
+       TEXT_STAT_FLAGS =
 endif 
 
 
@@ -44,8 +46,8 @@ check:
 
 all:  
        ${CC} ${CCFLAGS} -dynamiclib bar.c space.s -Os -o libbar.dylib  ${TEXT_RELOC_FLAGS}
-       ${CC} ${CCFLAGS} bind.c -static -Os -c -o bind.o
-       ${CC} ${CCFLAGS} -dynamiclib bind.o libbar.dylib -o libbind.dylib ${TEXT_RELOC_FLAGS}
+       ${CC} ${CCFLAGS} bind.c $(TEXT_STAT_FLAGS) -Os -c -o bind.o
+       ${CC}  -dynamiclib bind.o libbar.dylib -o libbind.dylib ${TEXT_RELOC_FLAGS}
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib libbind.dylib
        
 clean:
index 2767b5d7aa4991f811e32a872f6f5fcd0cf93c6f..0593e1e8d0ccb9d2a136c7d2c9440c456e6ca53c 100644 (file)
@@ -1,2 +1,3 @@
        .text
+       .align 2
 _junk: .space  1024*1024
index 62cd36a3d39d2a5c99cc0bc5f90fbfd7c824fc1e..6a6d74c3bacf117f89dfb54bdb2db8f9b0e740aa 100644 (file)
@@ -28,9 +28,9 @@ include ${TESTROOT}/include/common.makefile
 ## Basic test of thread-local-variables in a main executable
 ##
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_:
        ${PASS_IFF} true
index 5116395d2456ad130e114dac876c71228fc6aa4d..919667ab32379bd402d1dd419df7ac078a40b844 100644 (file)
@@ -1,98 +1,17 @@
 
-               # _a is zerofill global TLV
-               .tbss _a$tlv$init,4,2
-
-               # _b is an initialized global TLV
-               .tdata
-_b$tlv$init:    
-               .long   5
-
-
 #if __x86_64__
 
-               # _a isĀ global TLV
-               .tlv
-               .globl _a
-_a:            .quad   __tlv_bootstrap
-               .quad   0
-               .quad   _a$tlv$init
-
-               # _b is a global TLV
-               .tlv
-               .globl _b
-_b:            .quad   __tlv_bootstrap
-               .quad   0
-               .quad   _b$tlv$init
-
-               # _myinit sets up TLV content
-               .thread_init_func
-               .quad   _myinit
-
-
-       .text
-       .globl  _get_a
-_get_a:
-       pushq   %rbp
-       movq    %rsp, %rbp
-       movq    _a@TLVP(%rip), %rdi
-       call    *(%rdi)
-       popq    %rbp
-       ret
-
-       .globl  _get_b
-_get_b:
-       pushq   %rbp
-       movq    %rsp, %rbp
-       movq    _b@TLVP(%rip), %rdi
-       call    *(%rdi)
-       popq    %rbp
-       ret
+    # _myinit sets up TLV content
+    .thread_init_func
+    .quad      _myinit
 
 #endif
 
 #if __i386__
 
-               # _a isĀ global TLV
-               .tlv
-               .globl _a
-_a:            .long   __tlv_bootstrap
-               .long   0
-               .long   _a$tlv$init
-
-               # _b is a global TLV
-               .tlv
-               .globl _b
-_b:            .long   __tlv_bootstrap
-               .long   0
-               .long   _b$tlv$init
-
-               # _myinit sets up TLV content
-               .thread_init_func
-               .long   _myinit
-
-
-       .text
-       .globl  _get_a
-_get_a:
-       pushl   %ebp
-       movl    %esp, %ebp
-       subl    $8, %esp
-       movl    _a@TLVP, %eax
-       call    *(%eax)    
-       movl    %ebp, %esp
-       popl    %ebp
-       ret
-
-       .globl  _get_b
-_get_b:
-       pushl   %ebp
-       movl    %esp, %ebp
-       subl    $8, %esp
-       movl    _b@TLVP, %eax
-       call    *(%eax)    
-       movl    %ebp, %esp
-       popl    %ebp
-       ret
+    # _myinit sets up TLV content
+    .thread_init_func
+    .long      _myinit
 
 #endif
 
index af11a8629e741eb2ccc5ccc2f2230266179a0193..3f89123ec4898ab5d0348f243436eec2c1e8f14f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
-extern int* get_a();           // initially 0
-extern int* get_b();           // initially 5
+__thread int a = 0;            // initially 0
+__thread int b = 5;            // initially 5
 
+// simulate C++ initializer on thread local variables
 void myinit()
 {
-       *get_a() = 11;
-       *get_b() = 42;
+       a = 11;
+       b = 42;
 }
 
-
 static void* work(void* arg)
 {
        //fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
-       if ( *get_a() != 11 ) {
+       if ( a != 11 ) {
                FAIL("tlv-initializer: get_a() not initialized to 11");
                exit(0);
        }
-       if ( *get_b() != 42 ) {
+       if ( b != 42 ) {
                FAIL("tlv-initializer: get_b() not initialized to 42");
                exit(0);
        }
index f27c54e1084c0ca1cbbc9ff63bf338374e0b68aa..909473274504287e8df689d46d43b74b069e4e48 100644 (file)
@@ -28,9 +28,9 @@ include ${TESTROOT}/include/common.makefile
 ## Basic test of thread-local-variables in a main executable
 ##
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_:
        ${PASS_IFF} true
diff --git a/unit-tests/test-cases/upward-dylib-init-order/Makefile b/unit-tests/test-cases/upward-dylib-init-order/Makefile
new file mode 100644 (file)
index 0000000..a0a54a1
--- /dev/null
@@ -0,0 +1,53 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
+
+all: all_$(OS_LION_FEATURES) 
+
+check: check_$(OS_LION_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+
+all_1: 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib common.c -o libcommon.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib u.c libcommon.dylib -o libu.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib c.c libcommon.dylib -o libc.dylib -Wl,-upward_library,libu.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib b.c libcommon.dylib -o libb.dylib libc.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libb.dylib libu.dylib libcommon.dylib -o main
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libu.dylib libb.dylib libc.dylib libcommon.dylib
+
+
+       
diff --git a/unit-tests/test-cases/upward-dylib-init-order/b.c b/unit-tests/test-cases/upward-dylib-init-order/b.c
new file mode 100644 (file)
index 0000000..9a146f4
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include "common.h"
+
+
+
+static __attribute__((constructor)) void myInit() 
+{
+       setB();
+       //fprintf(stderr, "init b\n");
+}
diff --git a/unit-tests/test-cases/upward-dylib-init-order/c.c b/unit-tests/test-cases/upward-dylib-init-order/c.c
new file mode 100644 (file)
index 0000000..0d79e7c
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+
+
+static __attribute__((constructor)) void myInit() 
+{
+       //fprintf(stderr, "init c\n");
+}
diff --git a/unit-tests/test-cases/upward-dylib-init-order/common.c b/unit-tests/test-cases/upward-dylib-init-order/common.c
new file mode 100644 (file)
index 0000000..c703835
--- /dev/null
@@ -0,0 +1,29 @@
+#include "common.h"
+#include <stdio.h>
+
+static bool b = false;
+static bool u = false;
+static bool isOk = true;
+
+void setB()
+{
+       if ( u || b )
+               isOk = false;
+       b = true;
+}
+
+void setU()
+{
+       if ( u )
+               isOk = false;
+       u = true;
+}
+
+// return true iff
+// setB() was called, then setU()
+bool ok()
+{
+       //fprintf(stderr, "isOk=%d, u=%d, b=%d\n", isOk, u, b);
+       return isOk && u && b;
+}
+
diff --git a/unit-tests/test-cases/upward-dylib-init-order/common.h b/unit-tests/test-cases/upward-dylib-init-order/common.h
new file mode 100644 (file)
index 0000000..0094023
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdbool.h>
+
+extern void setB();
+extern void setU();
+
+extern bool ok();
+
diff --git a/unit-tests/test-cases/upward-dylib-init-order/main.c b/unit-tests/test-cases/upward-dylib-init-order/main.c
new file mode 100644 (file)
index 0000000..e7edc55
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "common.h"
+
+int main()
+{
+       if ( ok() )
+               PASS("upward-dylib-init-order");
+       else
+               FAIL("upward-dylib-init-order");
+        
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/upward-dylib-init-order/u.c b/unit-tests/test-cases/upward-dylib-init-order/u.c
new file mode 100644 (file)
index 0000000..81c4043
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include "common.h"
+
+
+static __attribute__((constructor)) void myInit() 
+{
+       setU();
+       //fprintf(stderr, "init u\n");
+}
+
index 9488bac33abf29a6f74cef3e8f3115016c83fa77..b33a842df15ffc654143812b7c44e7cac1d08e8d 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
 
-all: all_$(OS_BAROLO_FEATURES) 
+all: all_$(OS_LION_FEATURES) 
 
-check: check_$(OS_BAROLO_FEATURES)
+check: check_$(OS_LION_FEATURES)
 
 check_:
        ${PASS_IFF} true
@@ -43,8 +43,8 @@ all_1:
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib up.c -DSTUB -o libup.stub -install_name libup.dylib 
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib down.c -o libdown.dylib -Wl,-upward_library,libup.stub 
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib up.c libdown.dylib -o libup.dylib  
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libdown.dylib libup.dylib -o main2
        ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libup.dylib libdown.dylib -o main1
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main2.c  libdown.dylib  -o main2
 
 
 clean:
index c5624bdbfc462040b9884b4bb7f2535d776e23f9..f576ad6c688b50041bcea9fc632562d2c0e91357 100644 (file)
@@ -16,7 +16,7 @@ int getdown()
        return state;
 }
 
-void other()
+int getdownsup()
 {
-       whatsup();
+       return whatsup();
 }
\ No newline at end of file
index 534eb9241e499db407b039e7c2894ebb80258b34..e4eb56c6159a3c9dd1bbd505f3b381e824f1910b 100644 (file)
@@ -1,2 +1,3 @@
 extern int getdown();
+extern int getdownsup();
 
index 06b272bf3c721d82e667bee2292bdcc2ce15f00a..302478a78314e7e3d2ac45050a5003c2d2523a0c 100644 (file)
@@ -13,6 +13,7 @@ int main()
                PASS("upward-dylib");
        else
                FAIL("upward-dylib");
+        
        return EXIT_SUCCESS;
 }
 
diff --git a/unit-tests/test-cases/upward-dylib/main2.c b/unit-tests/test-cases/upward-dylib/main2.c
new file mode 100644 (file)
index 0000000..25ee4eb
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "up.h"
+#include "down.h"
+
+int main()
+{
+       if ( getdownsup() )
+               PASS("upward-dylib");
+       else
+               FAIL("upward-dylib");
+        
+       return EXIT_SUCCESS;
+}
+
+