From 832b6fce7c321434378950ecd081b6c34cc3a24f Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 27 Jul 2012 18:00:50 +0000 Subject: [PATCH] dyld-210.2.3.tar.gz --- doc/ReleaseNotes.txt | 1769 +++++++++++++++++ doc/man/man3/dlopen.3 | 16 +- dyld.xcodeproj/project.pbxproj | 171 +- include/mach-o/dyld_gdb.h | 2 +- include/mach-o/dyld_priv.h | 35 + include/objc-shared-cache.h | 1363 +++++++++++++ launch-cache/Architectures.hpp | 6 - launch-cache/MachOBinder.hpp | 49 +- launch-cache/MachOFileAbstraction.hpp | 36 + launch-cache/MachOLayout.hpp | 22 +- launch-cache/MachORebaser.hpp | 143 +- launch-cache/ObjCLegacyAbstraction.hpp | 19 +- launch-cache/ObjCModernAbstraction.hpp | 804 +++----- launch-cache/dsc_extractor.cpp | 68 +- launch-cache/dsc_iterator.cpp | 4 +- launch-cache/dsc_slider.cpp | 308 --- launch-cache/dyld_cache_format.h | 2 +- launch-cache/dyld_shared_cache_util.cpp | 23 +- launch-cache/update_dyld_shared_cache.cpp | 670 ++++--- src/ImageLoader.cpp | 69 +- src/ImageLoader.h | 47 +- src/ImageLoaderMachO.cpp | 202 +- src/ImageLoaderMachO.h | 2 +- src/ImageLoaderMachOClassic.cpp | 103 +- src/ImageLoaderMachOCompressed.cpp | 26 +- src/dyld.cpp | 311 +-- src/dyld.h | 3 +- src/dyldAPIs.cpp | 28 +- src/dyldAPIsInLibSystem.cpp | 138 +- src/dyldExceptions.c | 71 +- src/dyldInitialization.cpp | 16 +- src/dyldLibSystemGlue.c | 25 +- src/dyldLibSystemInterface.h | 2 + src/dyldStartup.s | 197 +- src/dyld_debug.c | 225 --- src/glue.c | 20 +- src/start_glue.s | 68 + src/stub_binding_helper.s | 65 - unit-tests/build-iPhoneOS-unit-tests | 4 +- unit-tests/include/common.makefile | 27 +- unit-tests/run-all-unit-tests | 2 +- .../DYLD_LIBRARY_PATH-dyld_env/main.c | 2 + .../Makefile | 16 +- .../main.c | 6 +- .../Makefile | 13 +- .../DYLD_VERSIONED_LIBRARY_PATH-basic/main.c | 2 + .../main.c | 2 + .../main.c | 2 + unit-tests/test-cases/addend/main.c | 29 + .../bundle-memory-load-fat/Makefile | 8 +- .../bundle-unload-keep-mapped/bundle.c | 2 +- unit-tests/test-cases/crt-apple/Makefile | 5 +- unit-tests/test-cases/crt-apple/main.c | 4 +- unit-tests/test-cases/crt-custom/Makefile | 2 +- unit-tests/test-cases/crt-custom/mystart.s | 1 + .../Makefile | 36 +- .../test-cases/dlopen_preflight-cycle/bar.c | 2 + .../test-cases/dlopen_preflight-cycle/baz.c | 1 + .../test-cases/dlopen_preflight-cycle/foo.c | 3 + .../test-cases/dlopen_preflight-cycle/main.c | 62 + .../fallback-non-unique-leaf-names/main.c | 2 + .../image-state-deny-all_image_infos/Makefile | 41 + .../image-state-deny-all_image_infos/bar.c | 1 + .../image-state-deny-all_image_infos/main.c | 82 + unit-tests/test-cases/image-suffix/main.c | 1 + .../initializer-bounds-check/Makefile | 2 +- .../initializer-bounds-check/main.c | 6 +- .../insert-libraries-with-suid/Makefile | 4 +- .../test-cases/interpose-shared-cache/main.c | 13 +- .../interpose-shared-cache/mymalloc.c | 29 +- .../test-cases/loader_path-symlink/Makefile | 49 + .../test-cases/loader_path-symlink/bar.c | 3 + .../test-cases/loader_path-symlink/foo.c | 3 + .../test-cases/loader_path-symlink/main.c | 14 + unit-tests/test-cases/pie-text-reloc/Makefile | 4 + .../re-export-symbol-dylib/Makefile | 59 + .../test-cases/re-export-symbol-dylib/bar.c | 5 + .../test-cases/re-export-symbol-dylib/baz.c | 5 + .../test-cases/re-export-symbol-dylib/baz.exp | 2 + .../test-cases/re-export-symbol-dylib/foo.c | 4 + .../test-cases/re-export-symbol-dylib/foo.exp | 4 + .../test-cases/re-export-symbol-dylib/frob.c | 5 + .../test-cases/re-export-symbol-dylib/main.c | 44 + .../test-cases/re-export-symbol/Makefile | 6 +- unit-tests/test-cases/read-only-stubs/main.c | 12 + .../test-cases/restrict-environ/Makefile | 4 +- .../rpath-dlopen-rm-executable/main.c | 1 + .../test-cases/rpath-introspection/Makefile | 44 + .../test-cases/rpath-introspection/foo.c | 3 + .../test-cases/rpath-introspection/main.c | 68 + .../rpath-loader_path-dlopen/main.c | 1 + unit-tests/test-cases/suid-environ/Makefile | 4 +- .../test-cases/symbol-resolver-basic/Makefile | 6 +- .../symbol-resolver-interposed/Makefile | 55 + .../symbol-resolver-interposed/foo.c | 44 +- .../symbol-resolver-interposed/foo.h | 3 + .../symbol-resolver-interposed/main.c | 48 + .../symbol-resolver-interposed/myfoo.c | 10 + .../symbol-resolver-pointer/Makefile | 6 +- .../terminator-bounds-check/Makefile | 36 + .../main.c | 36 +- unit-tests/test-cases/text-relocs-perms/foo.c | 10 + .../test-cases/text-relocs-perms/main.c | 13 + unit-tests/test-cases/text-relocs/Makefile | 10 +- unit-tests/test-cases/text-relocs/space.s | 1 + .../test-cases/tlv-initializer/Makefile | 4 +- unit-tests/test-cases/tlv-initializer/get.s | 93 +- unit-tests/test-cases/tlv-initializer/main.c | 16 +- .../test-cases/tlv-terminators/Makefile | 4 +- .../upward-dylib-init-order/Makefile | 53 + .../test-cases/upward-dylib-init-order/b.c | 10 + .../test-cases/upward-dylib-init-order/c.c | 8 + .../upward-dylib-init-order/common.c | 29 + .../upward-dylib-init-order/common.h | 7 + .../test-cases/upward-dylib-init-order/main.c | 19 + .../test-cases/upward-dylib-init-order/u.c | 10 + unit-tests/test-cases/upward-dylib/Makefile | 8 +- unit-tests/test-cases/upward-dylib/down.c | 4 +- unit-tests/test-cases/upward-dylib/down.h | 1 + unit-tests/test-cases/upward-dylib/main.c | 1 + unit-tests/test-cases/upward-dylib/main2.c | 20 + 121 files changed, 6114 insertions(+), 2335 deletions(-) create mode 100644 doc/ReleaseNotes.txt create mode 100644 include/objc-shared-cache.h delete mode 100644 launch-cache/dsc_slider.cpp create mode 100644 src/start_glue.s rename unit-tests/test-cases/{dyld-slide => dlopen_preflight-cycle}/Makefile (59%) create mode 100644 unit-tests/test-cases/dlopen_preflight-cycle/bar.c create mode 100644 unit-tests/test-cases/dlopen_preflight-cycle/baz.c create mode 100644 unit-tests/test-cases/dlopen_preflight-cycle/foo.c create mode 100644 unit-tests/test-cases/dlopen_preflight-cycle/main.c create mode 100644 unit-tests/test-cases/image-state-deny-all_image_infos/Makefile create mode 100644 unit-tests/test-cases/image-state-deny-all_image_infos/bar.c create mode 100644 unit-tests/test-cases/image-state-deny-all_image_infos/main.c create mode 100644 unit-tests/test-cases/loader_path-symlink/Makefile create mode 100644 unit-tests/test-cases/loader_path-symlink/bar.c create mode 100644 unit-tests/test-cases/loader_path-symlink/foo.c create mode 100644 unit-tests/test-cases/loader_path-symlink/main.c create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/Makefile create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/bar.c create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/baz.c create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/baz.exp create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/foo.c create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/foo.exp create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/frob.c create mode 100644 unit-tests/test-cases/re-export-symbol-dylib/main.c create mode 100644 unit-tests/test-cases/rpath-introspection/Makefile create mode 100644 unit-tests/test-cases/rpath-introspection/foo.c create mode 100644 unit-tests/test-cases/rpath-introspection/main.c create mode 100644 unit-tests/test-cases/symbol-resolver-interposed/Makefile rename launch-cache/dsc_slider.h => unit-tests/test-cases/symbol-resolver-interposed/foo.c (57%) create mode 100644 unit-tests/test-cases/symbol-resolver-interposed/foo.h create mode 100644 unit-tests/test-cases/symbol-resolver-interposed/main.c create mode 100644 unit-tests/test-cases/symbol-resolver-interposed/myfoo.c create mode 100644 unit-tests/test-cases/terminator-bounds-check/Makefile rename unit-tests/test-cases/{dyld-slide => terminator-bounds-check}/main.c (66%) create mode 100644 unit-tests/test-cases/upward-dylib-init-order/Makefile create mode 100644 unit-tests/test-cases/upward-dylib-init-order/b.c create mode 100644 unit-tests/test-cases/upward-dylib-init-order/c.c create mode 100644 unit-tests/test-cases/upward-dylib-init-order/common.c create mode 100644 unit-tests/test-cases/upward-dylib-init-order/common.h create mode 100644 unit-tests/test-cases/upward-dylib-init-order/main.c create mode 100644 unit-tests/test-cases/upward-dylib-init-order/u.c create mode 100644 unit-tests/test-cases/upward-dylib/main2.c diff --git a/doc/ReleaseNotes.txt b/doc/ReleaseNotes.txt new file mode 100644 index 0000000..33ce9ad --- /dev/null +++ b/doc/ReleaseNotes.txt @@ -0,0 +1,1769 @@ + +dyld-208 + Correct @path to still work with symlinks + +dyld-207 + dyld should give a better error message if you try to use a newer binary on older OS + backtraces of LC_MAIN binaries end in tlv_get_addr+136, instead libdyld should export "_start" symbol + Fix up @rpath based paths during introspection + Interposition tuples are not respected when binding with resolvers + +dyld-206 + Give some warning that DYLD_ env vars are disabled + +dyld-205 + Add dyld to uuidArray to enable symbolication of stackshots + +dyld-204.1 + fix initializer ordering of upwardly linked dylibs + +dyld-204 + dyld misreads very large addends + Perform method list sort even if __DATA,__objc_opt_rw is absent + Remove category attaching from dyld shared cache + Shared cache method list sorting breaks protocol extended type encodings + +dyld-203.1 + initializer not run in only upwardly linked dylib + +dyld-203 + update_dyld_shared_cache does not build with libc++ + dyld does not build with libc++ + Add functions to get min OS and sdk versions program was linked with + DYLD_FRAMEWORK_PATH not mentioned in dlopen() man page + dsc_extractor not updating LC_FUNCTION_STARTS + +dyld-202 + Get rid of crt1.o and jump straight into main() from dyld + image denied loading by gc_enforcer is left in dyld_all_images_info array + +dyld-201 + Use spin lock to guard sAllImageInfos + +dyld-200.3 + genCaches fails: "header size miscalculation 0x00006000" + +dyld-200.2 + dsc_iterator.cpp needs cases for v7 variants + +dyld-200 + update_dyld_shared_cache should accept an 'overlay' along with a 'root' directory option +Remove PowerPC support + +-------------- +dyld-199.5 (iOS 5) + Update initial image list size + +dyld-199.4 + genCaches fails: header size miscalculation + +dyld-199.3 + Repair ivar offsets in dyld shared cache + +dyld-199.2 + improve Xcode upload of iOS dylibs + +dyld-199.1 + correctly adjust ARM movw when in dyld shared cache + +dyld-199 + update_dyld_shared_cache requires weak-linked frameworks to be present at shared cache generation time + Remove armv7 variants from dyld + +dyld-198.1 + back out previous change DYLD_XXX restrict check + +dyld-198 + corrupt load commands can pass sniff test if 32-bit wraps around + dyld should restrict DYLD_XXX debugging facilities + dyld should not allow loading of dylibs without valid signatures +enable DYLD_PRINT_REBASINGS + +dyld-197 + dyld should range check the fixup location of all bindings + range check initializers and terminators to be within image + +dyld-196.2 + dyld should support new armv7 variants + +dyld-196.1 + support re-exported symbols from re-exported libraries + +dyld-196 + movw/movt don't work in dyld shared cache + + +--------------------- +dyld-195.3 (Mac OS X 10.7.0) + update_dyld_shared_cache missed libstdc++? + i386 dyld shared cache overflows after adding libclh.dylib + +dyld-195.2 + spurious warning about embedded framework not being put in dyld shared cache + +dyld-195 + C++ 0x thread_local destructor support + update_dyld_shared_cache -verify finds differences + more verbose messages when vm_protect() fails + +dyld-194.1 +Fix uses of libc++abi-static.a + +dyld-194 + make interposing available to open source + __thread implementation doesn't preserve enough registers (ABI issue) + clang built update_dyld_shared_cache fails at runtime + +dyld-193 + dyld should honor CS_RESTRICT in _main like hasRestrictedSegment + update_dyld_shared_cache -overlay optimizations + +dyld-192.1 + dyld has NULL paths in image info array + +dyld-192 + dyld's map+slide should be an all or nothing operation + +dyld-191.3 + overriding shared cache dylibs with resolvers fails + +dyld-191.2 + dyld_stub_binder called repeatedly for $VARIANT$ functions + update_dyld_shared_cache crash when fat dylib truncated + +dyld-191.1 + update_dyld_shared_cache is failing + +dyld-191 + ASLR/PIE: dyld's "random padding" algorithm is deterministic + race condition with flat-namespace lazy binding + libdyld fails to build with clang-127 + +dyld-190.1 +remove libdyld.a target + +dyld-190 + _NSGetExecutablePath documentation is ambiguous about bufsize + 11A315: LC_DYLD_ENVIRONMENT does not expand @executable_path + dyld should avoid arc4random for dylib randomization + tune trie traversal code for 10.7 compiler + breaking libSystem into dylibs slows down dyld binding, shared cache should compensate + update_dyld_shared_cache should not be built no-pie + +dyld-189 + dyld(1) man page feedback + LC_DYLD_ENVIRONMENT should still be honored with __RESTRICT,__restrict section present + 11A307: DYLD_SHARED_REGION=private crashes + don't slide shared cache if ASLR disabled (main executable didn't slide) + +dyld-188 + Dynamic linking memory usage seems unusually high for trivial programs + +dyld-187 + madvise MADV_FREE calls for LINKEDIT are failing in dyld during launch in iOS + dyld allImageInfos messed up with duplicate IOKit + +dyld-186 + dyld: Pick up changes from libsystem_kernel reorganisation in dyld's build. + Shared Region Base Should Slide at Boot Time + Multiple /dev/urandom accesses on every process exec + +dyld-185 + text relocs don't work if only S_ATTR_EXT_RELOC is used + DYLD_FORCE_FLAT_NAMESPACE=YES causes process to spin in DYLD-STUB$$bzero + +dyld-184 + Add cache slide value to dyld_all_image_infos + +dyld-183.1 + dyld proper does not need dyld_stub_binder.o + +dyld-183 + dyld needs to call new kernel interface to register metadata + ASLR side build causes 15-30% regression in most launch times + Support version-checked framework/library override paths + Support LC_DYLD_ENVIRONMENT load command + function starts info should be copied into dyld shared cache + +dyld-182 + Merge Jasper dyld changes to trunk + +dyld-181.1 + 11A270: FNPLicensingService crashes + +dyld-181 + 11A238a: AutoDesk AutoCAD beta 4 crashes on launch (dyld) + update_dyld_shared_cache-173 project fails to build with LLVM compiler 2.0. + +dyld-180 + 8F63: dyld-179.4 fails on missing /usr/local/lib/system/libc.a + 11A238a: AutoDesk AutoCAD beta 4 crashes on launch + 11A244: overlapping files in libdyld & update_dyld_shared_cache + + +dyld-179.7 (iOS 4.2) + range check initializers + +dyld-179.6 + dyld_shared_cache_extract_dylibs shouldn't return '-1' when arch already exists + +dyld-179.5 + Need a version of dyld_shared_cache_extract_dylbs that lipo's results + Need a version of dyld_shared_cache_extract_dylbs that reports progress + back out work around for 8151909 + +dyld-179.4 + images in shared cache are bound against different IOKit than found at runtime + +dyld-179.3.1 + 11A245: Photoshop CS4 fails in SmokeTest because of crash in FNPLicensingService (dyld) + +dyld-179.3 + 11A238a: All Adobe CS4 applications crash on launch + +dyld-179.2 + 11A239: leaks throws an exception, doesn't work + +dyld-179.1 + libdsc.a in Jasper SDK needs to be arm version (is x86 version) + +dyld-179 + update_dyld_shared_cache does not work with individual symbol re-exports + +dyld-178 + Support __thread variables exported from dylibs + update dyld_all_image_infos more often, for better crash logs + +dyld-177 + We need an extractor able to pull the shared symbols cache apart + Don't put slide info in dyld shared cache in Jasper + dyld does not prevent loading of unsigned dylib + +dyld-176 + split seg info wrong for x86_64 stub helpers + +dyld-175 + ObjC optimized shared cache does not slide + +dyld-174 + Need to merge Apex ObjC method list optimizations in dyld shared cache to TOT dyld + implement ASLR for dyld shared cache for iOS + +dyld-173 + fix permissions on rebased binary not slid + +dyld-172.2 + dyld should not include SystemIntegrity headers on embedded platform +Have DYLD_PRINT_BINDINGS print out when resolver functions are called + +dyld-172.1 + 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 + ER: more metadata for dyld errors + +dyld-169 + update_dyld_shared_cache needs to support resolver functions +Implement some cxa stuff to work with next c++abi.a + +dyld-168 + dyld should move shared cache file into /var/run instead of open-unlinking + private shared cache calls mmap twice for each range + Loading MH_DYLIB_STUB causing coalescable miscount + 11A168: update_dyld_shared_cache problems during install + use of C++ thread local initializer causes infinite recursion + (from iPhoneOS) dyld should stub out mach_error_string for 8KB RAM savings per process + (from iPhoneOS) verify that replacement is in this image + +dyld-167.2 + dyld: Use libsystem_mach.a from /usr/local/lib/dyld to build dyld + +dyld-167.1 + dyld should move shared cache file into /tmp instead of open-unlinking + +dyld-167 + dyld support for function specialization + dyld should directly call __cxa_finalize(), part 2 + dyld support for thread local variables + + +dyld-166 + ER: facility to detect which images were loaded at runtime + update_dyld_shared_cache -verify fails + + +dyld-165 + update_dyld_shared_cache should suppress warnings for embedded frameworks + Sort method lists in dyld shared cache + + +dyld-164 + Move libdyldapis over to a dylib target for Libsystem + pruneEnvironmentVariables does not update gLinkContext.apple + + +dyld-163 + Warning message is misleading + update_dyld_shared_cache should not run past end of splitseginfo if zero terminator is missing + dyld should directly call __cxa_finalize(), part 1 + + +dyld-162 + crash in update_dyld_shared_cache when checking if current cache is out of date + ER: Support upward dylib dependencies + + +dyld-161 + __builtin_return_address broke for PPC + SWBDC error: 'ld: duplicate symbol' while building 'dyld-160~48' in '11A108a-llvmgcc-2324.3' + + +dyld-160 + Environment variable to cause dyld to dump rpaths used during loading + update_dyld_shared_cache failed: internal error, new trie allocated to far from fLinkeditBase + dyld still slides executables when PIE is disabled by the kernel + + +dyld-159 + update_dyld_shared_cache fails to find roots when targetting NFS + dyld does not call initializers from all S_MOD_INIT_FUNC_POINTERS sections + move _dyld_func_lookup prototype to dyld_priv.h + + +dyld-158 + dyld attempts to load libraries via rpath when already loaded + dyld shared cache can be more random + + +dyld-157 + switch to use libc++abi-static.a instead of libstdc++-static.a + + +dyld-156 + remove DYLD_NO_PIE from man page + support multiple dylibs with non-intersected weak symbols in shared cache + dyld sends bogus library unload notice to CoreSymbolication during dlopen_preflight() + spelling: "was build against" -> "was built against" + + +dyld-155 + sjlj based exception support needs to be conditionalized for arm - not iPhoneOS + + +dyld-154 + Need to enable CoreSymbolication load/unload notices on iPhoneOS + + +dyld-153 + add field to dyld_all_image_infos pointing to dyld_all_image_infos + + +dyld-152 + Minimize system calls and mach messages during dyld startup + Why is checkSharedRegionDisable() !__LP64__ + + +dyld-151 + dyld support for sliding PIE binaries in the kernel + libdyld does not install multiple headers at installhdrs time + dlopen() crash when executable contains LC_RPATH and executable file is deleted while running + leak in dyld during dlopen when using DYLD_ variables + + +---------------------------------- + +dyld-150 ( iPhoneOS 3.1 ) + flat_namespace linkage error in update_dyld_shared_cache should be a warning not an error + Have dyld save load addr + UUID for executable images + Libsystem fails to link with latest gcc: dyld missing _dyld_func_lookup + + +dyld-149 + dlopen() not working with non-canonical paths + update_dyld_shared_cache fails creating shared cache + + +dyld-148 + shared cache file offsets are inconsistent + + +dyld-147 + move install location for update_dyld_shared_cache and man page to local + imageFileModDate in dyld_all_image_infos is sometimes bogus for the first image therein + dyld_shared_cache_util should optionally print VM load addresses for each dylib + uuid_t not defined in dyld_priv.h + + +dyld-146 + Save load information (load addr + UUID) to dyld_all_image_infos for images from outside the shared cache + update_dyld_shared_cache should improve warning above deployment target + + +dyld-145 + optimize stubs in dyld shared cache to be no-PIC + dyld_shared_cache_util built by dyld target should go in platform directory + dyld_shared_cache_util should list LC_REEXPORT_DYLIB libraries as dependents + + +dyld-144 + dyld_shared_cache_util built by dyld target should go in platform directory + API: Detect shared cache overrides + + +dyld-143 + ER: Tool to list the contents of a dyld shared cache image + ARM support for dsc_iterator + + +dyld-142 + text relocs fail in large segments + Variable whose data is overwritten needs to be marked `volatile' + dyld option to print time for each initializer, Apple's or the app's + + +dyld-141 + update_dyld_shared_cache assumes -root path contains no symlinks +sync with SnowLeopard dyld-132.13 + + +dyld-140 + load code signature from file, and before mapping the file + + +dyld-139.1 + Northstar7C62: dyld-139 fails to build + + +dyld-139 + dyld on iPhoneOS uses libgcc_eh.a which uses pthread_key_create which does not work + dyld can leak when an internal exception in thrown + support compressed LINKEDIT on iPhone +sync with SnowLeopard dyld-132.11 + + +dyld-138.1 + New mechanism to instruct dyld whether to check for libs outside the shared cache + + +dyld-138 + need to handle symlinks when dylib is in cache but file is intentionally missing + dyld should avoid stat()ing libraries present in the shared cache unless magic override file is present + + +dyld-137 + 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 + dyld reports bogus fat offset when registering shared cache signature + + +dyld-135 + iPhone: Need objc optimizations in iPhone OS shared cache + + +dyld-134 + build armv6 dyld with Thumb +sync with SnowLeopard + + + +dyld-133.1 +fix for all arm architectures + + +dyld-133 + make dyld that uses shared cache on iPhone OS + + +---------------------------------- + +dyld-132.13 ( Mac OS X 10.6 ) + classic images not unmapped when unloaded + + +dyld-132.12 + dyld's dtrace notification should be done after rebasing + + +dyld-132.11 + Remove dyld workaround for McAfee VirusScan + Add gating mechanism to dyld support system order file generation process + + +dyld-132.10 + dyld's abort_report_np() doesn't abort + 10A331: CUPS crashes when calling sandbox_init + + +dyld-132.9 + dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized + Exception Backtrace being obscured by _mh_execute_header + Silverlight Preferences.app crashes + + +dyld-132.8 + dlopen() leaks send right obtained from mach_thread_self() + dyld's calloc() allocates too few bytes + dyld lazy binding is not thread safe + + +dyld-132.7 + need a way other than setgid to have dyld launch a process securely, ignoring DYLD_ env vars etc + Need mapping of files to their offsets into the dyld_shared_cache files on disk + + +dyld-132.6 + update_dyld_shared_cache -overlay should check root dyld caches + NSCreateObjectFileImageFromMemory() call vm_deallocate even if application used malloc() + + +dyld-132.5 + dyld is missing some binding optimizations + symbol lookups in the new trie structure should be faster + weak binding done too early with inserted libraries + + +dyld-132.4 + improve statistics output + better error message if LC_RPATH is used in dylib destined for shared cache + dladdr() broke when image has debug symbols + 10A264: Google Earth 5.0 crashes on quit + man page should better explain update_dyld_shared_cache -root option + + +dyld-132.3 + remove setjmp/longjmp from _simple_printf in dyld + Typo in dyld(3) man page + race condition in pre-10.6 style lazy pointer binding + make cheaper dladdr() that just returns image path + 10A266 - Adobe InDesign CS4 crashes on launch + dyld is not setting imageFileModDate in dyld_image_info + Logic Pro crashes after creating a new document on SnowLeopard + + +dyld-132.2 + adopt new CoresSymbolication notification mechanism + Alter libdyld.a to not need libsystem to link with dylib1.o + 10A256a: update_dyld_shared_cache -verify crashes (probably due to lack of a shared cache) + + +dyld-132.1 + update_dyld_shared_cache failed: no writable segment in Cocoa framework + + +dyld-132 + CrashTracer: [USER] 1 crash in Neverwinter Nights 2 + + +dyld-131 + libgmalloc broken on 10A10246 and 10A251 (libgmalloc not inserted early enough) + + +dyld-130 + Rosetta circular dependency spew + @rpath and @loader_path Should be Documented in man page +Prune unneeded load commands from shared cache images + + +dyld-129 + dyld-128 no longer builds for armv6 + 10A244: iTunes crashes trying to load MobileDevice.framework + + +dyld-128 + ImageLoader objects can be made smaller + dyld spin in SecurityAgent + ImageLoaderMachO::makeImportSegmentWritable() doesn't do it + + +dyld-127 + Add all_image_infos for CrashReporter +some fixes for compressed LINKEDIT + + +dyld-126 + x86_64 export trie nodes may have large negative address + update_dyld_shared_cache man page should be updated to reflect new SL behavior + + +dyld-125 + @rpath and @loader_path should be documented in man page + Add NOP after trap instruction in _dyld_fatal_error + + +dyld-124 + 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 + Add -verify option to update_dyld_shared_cache + [dyld] Errors reported by the upcoming compiler flags verifier + 10A224: update_dyld_shared_cache warns about a condition in B&I-built frameworks + stop shadowing old data structures + dyld implicit-libSystem breaks valgrind + + +dyld-122 + Need a way to determine if a gdb call to dlopen() would block + Drop Rosetta shared cache generation by default / at install + "terminaton function" misspelled + Make it easier to use shared caches from foreign systems + SnowLeopard10A210: MATLAB 7.6 crashes on launch + + +dyld-121.1 + CrashTracer: crash in iTunes at com.apple.QuickTimeComponents.component + + +dyld-121 + libdyld.a is missing dyld_stub_binder + + +dyld-120 + 10A197 - After Effects 8.0.2 fails to launch after installation + + +dyld-119 + 10A212: update_dyld_shared_cache failed: string buffer exhausted + Oracle client crashes + + +dyld-118.1 + Cope with duplicate protocol references in shared cache construction + + +dyld-118 + 10A197 vs 10A190: Applications warm launch time slowdown due to dyld + + +dyld-117 + 10A198 - Final Cut Pro 6.0.4 crashes on launch [INTRODUCED BY dyld-115 IN 10A197] + + +dyld-116 + Pandora Desktop (Adobe AIR Framework) crashes on launch [INTRODUCED BY dyld-101 IN 10A14] + dyld should use libunwind + Possible leak originating in speech at LoadEngine + update_dyld_shared_cache manpage typos 'parition', 'assignes', 'choosen' + + +dyld-115 + LINKEDIT content could be greatly compressed + + +dyld-114 + update_dyld_shared_cache needs to provide progress that the Installer can display + update_dyld_shared_cache needs to be able to look at an Installation sandbox + dyld isn't calling csdlc_notify on library unload + warning, could not bind Mail.app because realpath() failed on /AppleInternal/.../XILog.framework + + +dyld-113 + NSAddressOfSymbol(NULL) should return NULL and not crash + dlopen() should fail to load (non-pie) executables + + +dyld-112 + _replacement misspelled as _replacement in dyld-interposing.h + make _dyld_find_unwind_sections() faster + + +dyld-111 + improve bad relocation error message + Need load/unload notification sent to com.apple.vmudl service when requested + _replacement misspelled as _replacement in dyld-interposing.h + + +dyld-110 + check libSystem is correct in shared cache file before loading it + function names returned by dladdr do not match reality + update_dyld_shared_cache .map files should be written atomically + dlopen(RTLD_NOLOAD) does not need to throw an internal exception + Explanation for the RTLD_NEXT flag in dlsym(3) needs clarification + DYLD_FALLBACK_LIBRARY_PATH should not apply to dlopen() of a partial path + No shared cache present on first boot + + +dyld-109 + Safe Boot should disable dyld shared cache + CrashTracer: crash in preFetch() reading off end of LINKEDIT + DYLD_NO_PIE env variable should be documented in dyld manpage + put all dylibs in shared cache - not just ones used by more than one app + Leaked fSegmentsArray and image segments during failed dlopen_preflight + + +dyld-108.1 + armv7/armv5 specific settings needed for dyld + dyld shouldn't set VALID_ARCHS + + +dyld-108 + ER: dyld based Objective-C selector uniquing + + +dyld-107 + update_dyld_shared_cache should require all source dylibs be owned by root + Limit what might go in the dyld shared cache + DYLD_ROOT_PATH should apply to LC_RPATH rpaths + Grow initial dyld pool if needed + there should be some way to temporarily turn off -pie + If pie, ignore preferred load address + 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 + dyld error handling fails in low memory, _simple_salloc() result not checked + dyld should provide executing program name in incompatible cpu-subtype error message + + +dyld-105 + It should work to set DYLD_FALLBACK_LIBRARY_PATH to empty + Remove the exceptions made in 4804594 for filemaker + Remove Tiger-era hacks in dyld for old app compatibility + Make RTLD_MAIN_ONLY public + die more gracefully when load commands are malformed + SWB: dyld build failure when built with -fstack-protector + dyld man page mis-spelling + update_dyld_shared_cache does not work when run manually + + +dyld-104 + The optimization to reuse install names as fPath was lost + Add JIT field to dyld_all_image_infos +Add _dyld_find_unwind_sections() + + +dyld-103 + NSLinkModule() can crash + dyld: obsoleted deprecated APIs +work around for +add test cases for lazy dylib loading + + +dyld-102 + Man page typo for update_dyld_shared_cache + Add "malloc is initialized" to the dyld_all_image_infos struct + better handling of open() errors + remove + Use instead of + dyld and libdyld should not force building with gcc 4.0 + + +dyld-101 + make it easier to find dyld_all_image_infos + Need _dyld_get_image_slide(const struct mach_header* mh) + dyld: push code signatures for libs to kernel + + +dyld-100 + dyld falls over when asked to map a split seg library not in the shared region + dyld: interposing does not work when replacee is thumb + dyld: all PIE programs crash on launch + BigBear: not loading libraries at their preferred addresses + dyld support for arm subtypes + dyld's prefetching should be turned off for prebound images (and perhaps entirely?) + dyld-95.3 doesn't build with gcc 4.2 +merge in arm support + ADOBE: Premiere Pro crashes on quit + +---------------------------------- + +dyld-96.2 (Mac OS X 10.5.2) + 10.5.2 Regression: 9C18 MeetingMaker crash on launch + +dyld-96.1 + update_dyld_shared_cache can crash if dylibs modified out from under it + crash when dyld interposes on system with partially invalid cache + com.apple.dyld message spew + CFSTRs cause crashes in Leopard + if system shuts down during update_dyld_shared_cache, tmp file is never cleaned up + dlopen() and dlopen_preflight() can leak on failure + + + +dyld-95.3 (Mac OS X 10.5) + Increase initial dyld pool size for 64-bit programs + + +dyld-95.2 + make ppc dyld cache a different file for rosetta + + +dyld-95.1 + McAfee VirusScan fails to launch on Leopard9A513 + + +dyld-95 + 9A516 - Keep getting disk full errors + + +dyld-94 + Leopard (9a499): dyld crash with recursive calls to dlclose() + + +dyld-93 + FileMaker Server 8.0v4 helper tools broken by @executable_path security change + Use msync(MS_SYNC) when building dyld cache + + +dyld-92 + Skype Crashes during launch + + +dyld-91.2 + dlopen() looks too far up stack, can cause crash + + +dyld-91.1 + dyld warning about dtracehelper is too noisy? + Lots of task_self_trap() system calls in ImageLoader::recursiveInitialization() + + +dyld-91 + use of @loader_path based RPATH can cause dyld to leak + Dyld_stubs should not be writable on x86 + + +dyld-90.2 + generating dyld shared cache generation on first boot makes time to MacBuddy very slow + + +dyld-90.1 + truncated dyld cache file after panic causes hang at boot + + +dyld-90 + stop special casing main executables initializers + DYLD_INSERT_LIBRARIES doesn't work correctly with initializer functions + + +dyld-89 + dyld could asynchronously request pages it will need + handle when argv[0] is NULL. + Foundation built on 9A436 doesn't launch 64 bit apps +partial fix for: Dyld_stubs should not be writable on x86 + + +dyld-88 + update_dyld_shared_cache keeps spewing messages to console + optimize LINKEDIT region of dyld shared cache + Support extended __dyld section with NXArgc, etc addresses +remove call to __xlocale_init() +Update __OPEN_SOURCE__ conditionals + + +dyld-87 + CFM games use private _dyld_fork_* routines - add back + better handling of NOLOAD with symlinked dylibs + + +dyld-86.1 +Fix DYLD_SHARED_REGION=private +update man page + + +dyld-86 + update_dyld_shared_cache fails on @executable_path framework + [Leopard]: 9A441/442: unable to log in after switching to arabic + dlopen via CFBundleLoad keeps searching after finding a loadable object + + +dyld-85.2 + 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 + Leopard9A447: Meeting Maker and Microsoft apps will not launch on Intel. + + +dyld-85 + 9A436: Adobe: Photoshop CS3 crashed on pressing Command-C after Command-A + Use _dyld_initializer + + +dyld-84 + 9A438 dlopen_preflight() corrupts all_image_info list causing Symbolication crashes + B&I needs an ENV variable to turn off "dyld: ioctl to register dtrace DOF section failed" warnings + remove support for __image_notify sections +remove all update_prebinding code + + +dyld-83 + 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 + update_dyld_shared_cache error message gives an errno value rather than an error string + dyld interposing doesn't work with dlsym() lookup + dlopen_preflight() of MH_BUNDLE leaks + integrate ImageLoader changes into leopard dyld + translated (ppc) dyld should not attempt to register DOF sections + Some dyld library paths are not canonicalized, causing tools using those paths to defenestrate themselves + + +dyld-82.5 + REGR: Leopard9A419: Firefox hangs on launch + + +dyld-82.4 + Leopard9A420: interposing of libMallocDebug or libgmalloc broken +Fix so problems like are warnings instead of errors + + +dyld-82.3 + 9A420: dyld: ioctl to register dtrace DOF section failed + + +dyld-82.2 + dyld frees string returned by dyld_image_state_change_handler + better handling than "corrupt binary, library ordinal too big" + + +dyld-82.1 + dyld changes needed to support read-only DOF + + + +dyld-82 + don't need to hold dyld global lock while running initializers + dyld leaks when dlopen fails + dyld leaks two blocks after bundle unload + + +dyld-81 + auto update dyld shared caches if missing or out of date + + +dyld-80.1 + Erronious "unsafe use of @rpath" dyld error + 9A384: update_dyld_shared_cache fails after ditto'ing matador root with debug info + Uninitialized ImageLoader->fRegisteredDOF field + + +dyld-80 (Leopard9A400) + Use new shared region syscalls + @rpath does not work with -rpath @executable_path/... + Firefox causes segfault during update_dyld_shared_cache + + +dyld-79.3 + Use new shared region syscalls + +dyld-79.2 + @rpath does not work with -rpath @executable_path/... + +dyld-79.1 (Leopard9A396) +fix use of LC_REEXPORTED_DYLIB + + +dyld-79 (Leopard9A392) + Support Apple PIE (address space randomization) + update_dyld_shared_cache should warning and not quit if a specified root is missing + DOF registration needs to switch from /dev/helper to /dev/dtracehelper + don't error out when a cache line crossing i386 stub cannot be bound + + +dyld-78.2 (Leopard9A387) + 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 + when loading a bundle, dyld is not making a copy of name + 9A343 KidPix 3 : SpellChecker bundle is not loaded + 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 + Use _dyld_initializer + Look at reduction/elimination of per-framework cost (don't touch __dyld section) + libdyldapis.a: make initialization as lean as possible + dyld should malloc never-to-be-freed blocks from its own pool + 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 + hang at boot, Libc changes + +dyld-76.1 + x86_64: dyld share cache does not work for AppKit + + +dyld-76 + Rosetta apps crash after update_dyld_shared_cache + Long-standing typo for "file to short" error from dlopen() / dlerror() + + +dyld-75.1 +Enable ppc shared cache generation on intel machines + + +dyld-75 + 64-byte crossing fast stubs should be bound early to avoid threading issues + support new intel stub segment that is marked not-writable + + +dyld-74 + register dtrace DOF sections with kernel + 10.4.9 Regression: Math Kernel crash with TiNovi 8P114 + + +dyld-73.2 + Leopard 9A921: Dyld error "lazy pointer not found" loading/running java + + +dyld-73.1 (Leopard9A328) + 9A326: update_prebinding crashes at end of install + + +dyld-73 (Leopard9A326) + REGR: 9A322 All Java apps crashing at dyld's misaligned_stack_error + + +dyld-72 (Leopard9A322) + Maya 8 crashes on launch on Leopard9A309 + ProTools 7.1.1cs1 for Intel hangs on launch on Leopard9A309 + x86 crashes in the binding helper do not have proper backtrace + + +dyld-71 (Leopard9A320) + inform rosetta of each library in the dyld shared cache + 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) + 9A305: Firefox 2.0 crashes on launch + httpd is dying in dyld after libobjc.dylib is unloaded + + +dyld-69 (Leopard9A305) + ER: dlclose() should be able to unload dylibs + runtime support for RPATH + + +dyld-68 (Leopard9A296) + rosetta doesn't work when shared cache is present + shared cache for 64-bit archs does not work when some dylibs are invalid + + +dyld-67.1 (Leopard9A292) + support 64-bit programs built with new 10.5 subtype + + +dyld-67 + CrashReporter needs a new way to distinguish fatal dyld errors + 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) + dyld fails to build with Libc changes in 4632326 + support 64-bit programs built with new 10.5 subtype + + +dyld-66.2 (Leopard9A260) + Leopard9A259: Backtraces in crash reports are not getting symbolicated + 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 + is in Darwin but not Dev Tools package + export shared range regions for gdb + __pthread_tsd_first appears to be initialized too late in dyld + 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) + jump table entry at end of segment can crash + Mathematica 5.2 (64-bit MathKernel) always crashes on 9A229 + dlsym man page needs to be more specific about RTLD_DEFAULT + Change wording in SEARCHING section in dlopen man page + Man page for dyld has misspelling: cheep + dyld(3) man page should point to Mach-O Programming Topics URL + + +dyld-64 (Leopard9A224) + No man page for dlopen_preflight(3) + dyld lazy binding of fast stubs is not completely thread safe + remove use of load_shared_file() + + +dyld-63 (Leopard9A215) + Would like way to quiet dynamic loader + deprecated old APIs for Leopard + NSCreateObjectFileImageFromMemory crashes when image is a MH_EXECUTABLE + + +dyld-62.1 (Leopard9A206) + prebound old stubs failure prevents uTest from running on i386 + + +dyld-62 (Leopard9A202) + an image with an open non-zero base address does not load more efficiently + Leopard9A190: NSAddImage() crashes when called from x86_64 process + /usr/lib/libAPSimple.dylib: mmap error + need to force interposing for rosetta processes + + +dyld-61 (Leopard9A179) + dyld calls close(-1) + _stub_binding_helper_interface isn't using movdqa + dyld tries to mmap 0 size segments and fails with conforming mmap + Load dyld above 4GB for x86-64 +Move apple parameters on stack when DYLD_ variables are removed + + +dyld-60 (Leopard9A160) + Suresec #203: dyld environment with suid binaries + SureSec si#187 linker: environment variables + print warning message if DYLD_INSERT_LIBRARIES is set (then ignored) for a setuid/setgid program + dyld's disableIfBadUser() routine can fail for constant strings + + +dyld-59 (Leopard9A156) + ER: dlopen_preflight() + + +dyld-58 (Leopard9A154) + implement RTLD_SELF + better handling of open() errors + would like dlopen(RTLD_FIRST) so that dlsym variant that does not search dependent libraries + dyld needs to adopt to Unix conformance changes + Crash on Leopard9A146 when GC rejects loading a library on Intel + + +dyld-57 (Leopard9A144) + pthread tsd entries doubly owned by DYLD and Libsystem... (Leopard) + dyld should automatically stop using the shared region if unavailable + If instantiateFromLoadedImage fails, dyld crashes + isCompatibleMachO needs to know about x86-64 + + +dyld-56 (Leopard9A140) + 64-bit dyld should load at around the last 4G - not in the first 4G + 64 bit: app crashes immediately if -pagezero_size >= 0x0ffffffff + dyld needs to build for x86-64 + dyld_debug API shim has leak + dyld does not slide properly on Intel + + +dyld-55 (Leopard9A138) + dlopen() should fail if bundle has objc code incompatible with runtime environment + libdyld: make non-POSIX header definitions visible when _POSIX_C_SOURCE is defined + A flat_namespace image with a reference to an internal private_extern should resolve immediately + dlopen() man page is missing RTLD_NOLOAD and RTLD_NODELETE + _CFExecutableLinkedOnOrAfter() fails on 64 bit + dyld needs to support x86-64 + + +dyld-54 (Leopard9A80) + remove ppc64 workarounds for fixed bugs + Memory error in removePathWithPrefix() + dyld does not properly swap CPU subtype from fat file header + dyld does not compile for open source + ADOBE XCODE 2.2: ZeroLink can cause wrong typeinfos to be used +Sync with Chardonnay (except for 4313830 and 4215516) + + +dyld-53 (Leopard9A42) + Add -fno-exceptions to Release target of libdyld + Wrong number of seconds reported by DYLD_PRINT_STATISTICS on Intel + + +dyld-52 (Leopard9Axxx) + dyld changes for new libstdc++ project + + +dyld-51 (Clueless) + STD:VSX: dlclose() should return non-zero value on failure. + STD:BUILD: dyld references non-conforming member name for PPC64 + The gdb list of images should be updated before dyld bases and binds each image + interposing does not handle stacking/nesting of interposing functions + use of DYLD_INTERPOSE() causes compiler warnings with -std=c99 -pedantic + SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371 + +dyld-50 (Leopard9Axxx) +Convert to build with gcc-4.0 + SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371 + +---------------------------------- + + + +dyld-46.16 (Mac OS X 10.4.11) + raise bail out limit in update_prebinding to 100 errors + +dyld-46.15 + [SUIncaSoho] update_prebinding can only handle 2MB of ppc unprebound dylibs on intel + update_prebinding fails if a prebound dylib depends on a non-prebound dylib + +dyld-46.14 + prebinding zeroes out files if an error occurs (such as no vm space left) + Rare & unknown root cause: Corruption of Kerberos framework during SU + +dyld-46.13 + dyld crashes starting threaded program + 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state + 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state + [SUTiSoHo] update_prebinding crashes when a weak linked dylib is missing + [SUIncaSoHo] update_prebinding crashes when a weak linked dylib is missing + +dyld-46.12 + 10.4.9 Regression: Math Kernel crash with TiNovi 8P114 + +dyld-46.11 + dyld's x86_64 support should be open source + 10.4.x: an image with an open non-zero base address does not load more efficiently + [SUTiNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately + [SUTiNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7 + [SUIncaNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7 + [SUIncaNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately + +dyld-46.10 + dyld-46.9 fails to build in Nicoya + +dyld-46.9 (Inca8K...) + jump table entry at end of segment can crash + +dyld-46.8 (Inca8K1073) + Mathematica 5.2 (64-bit MathKernel) always crashes on Inca + +dyld-46.7 (Inca8K1072) + dyld lazy binding of fast stubs is not completely thread safe + +dyld-46.6 (Inca8K1061) + Inca: don't write warning to stderr for setuid binaries + +dyld-46.5 (Inca8K1059) + prebound old stubs failure prevents uTest from running on i386 + +dyld-46.4 (Inca8K1057) + NSAddImage() crashes when called from x86_64 process + an image with an open non-zero base address does not load more efficiently + +dyld-46.3 (Inca8K1054) + need to force interposing for rosetta processes +re-enable setuid security fixes for 4525062 and 4525053 + +dyld-46.2 (Inca8K1046) + Adobe CS2 no longer launches + 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 ) + *SecUpd: Chardonnay* don't write warning to stderr for setuid binaries + *SecUpd: Tiger* don't write warning to stderr for setuid binaries + +dyld-45.2 (SUSecurity ) + *SecUpd: Chardonnay* SureSec si#187 remove all DYLD_ env vars for setuid binaries + *SecUpd: Tiger* SureSec si#187 remove all DYLD_ env vars for setuid binaries + *SecUpd: Chardonnay* Suresec #203: don't use $HOME with suid binaries + *SecUpd: Tiger* Suresec #203: don't use $HOME with suid binaries + + +dyld-45.1 (SUTiLondon...) +back out Suresec #203: dyld environment with suid binaries [SUTi] + + +dyld-45 (SUTiLondon...) + sync all 10.4.x dyld trains + dyld fix for gcc-3.3 C++ needs to get in SU + 64-bit dlopen crashes when opening fat bundle + SureSec si#187 linker: environment variables [SUTi] + Suresec #203: dyld environment with suid binaries [SUTi] + SureSec si#187 linker: environment variables [SUChard] + Suresec #203: dyld environment with suid binaries [SUChard] + +dyld-44.23 (Inca8...) + Crash using Core Image under Rosetta running InDesign CS2 w/ Magma Effects + +dyld-44.22 (Inca8K1030) + Stub binding helper changes for FP args for x86-64 + +dyld-44.21 (Inca8K1030) + printf doesn't work for x86-64 + +dyld-44.20 (Inca8K1029) + isCompatibleMachO needs to know about x86-64 + +dyld-44.19 (Inca8J1028) +two small x86_64 fixes + +dyld-44.18 (Inca8J1027) + dyld needs to support x86-64 + +dyld-44.17 (Chardonnay8G1152) + prebound fast stubs not ignored for flat_namespace dylibs + +dyld-44.16 (Chardonnay8G1141) + Sherlock often crashes in dyld::bindLazySymbol on launch + +dyld-44.15 (Chardonnay8G1137) + no apps can launch with /usr/lib/libMallocDebug.A.dylib on 8G1133 + +dyld-44.14 (Chardonnay8F1110) + System Integrity: changes needed for dyld + +dyld-44.13 (Chardonnay8F1108) + pthread tsd entries doubly owned by DYLD and Libsystem... (Chardonnay) + +dyld-44.12 (Chardonnay8F1108) + never pass shared_region_map_file_np() a zero-length region + +dyld-44.11 (Chardonnay8F1104) + dyld launch code should special case if there is only one prebound image with weak exports + +dyld-44.10 (Chardonnay8F1100) + dyld fails to link with Libc-391.1.13 + +dyld-44.9 (Chardonnay8F1093) + XCode2.1 + gcc 3.3 + C++ exception + Bundle Bug + low disk space code path executed with 44GB free + +dyld-44.8 (Chardonnay8F1079) + dyld lazy binding code should use movdqa + +dyld-44.7 (Chardonnay8B1072) + fix for rosetta crashes + +dyld-44.6 (Chardonnay8B1072) + Optimizing system should only progress once + +dyld-44.5 (Chardonnay8B1052) + New intel stub support + +dyld-44.4 (Chardonnay8B1051) + Leopard 9A14: Finder crashes burning a CD + dyld lazy binding code needs to save/restore all possible register parameters + use new libstdc++-static + +dyld-44.3 (Chardonnay8B1051) + dyld should recognize byte-swapped Mach-O files + dyld should only update prebound external relocations if they change + +dyld-44.2 (SUTiDenver8F10) [Mac OS X 10.4.3] + Tiger breaks NSCreateObjectFileImageFromMemory with fat Mach-O + dyld does not load libraries correctly if matching install_name in /usr/lib + CrashTracer: ..269 crashes at com.adobe.Acrobat.framework: RunAcrobat + 424 + +dyld-44.1 (Chardonnay) + __attribute__ ((regparm (3), stdcall)) doesn't work for inter-image calls + dyld should automatically set DYLD_SHARED_REGION to avoid + +dyld-44 (Chardonnay) + merge SUTiCambridge dyld and Karma dyld into Chardonnay + + +dyld-43.1 (SUTiCambridge8C20) [Mac OS X 10.4.2] +Update open source APSL headers + update_prebinding should gracefully handle low disk space + prebinding should not change n_value of .obj_class_name symbols + dyld gets into infinite loop with dlsym if dylib dependencies contain loops + FilesBuster crashed in dyld + DYLD_ROOT_PATH crashes program if any component does not start with / + dyld writes past end of buffer when checking environment variables + dyld_image_removing notification never sent + 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 +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. diff --git a/doc/man/man3/dlopen.3 b/doc/man/man3/dlopen.3 index 60c2527..679d267 100644 --- a/doc/man/man3/dlopen.3 +++ b/doc/man/man3/dlopen.3 @@ -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 diff --git a/dyld.xcodeproj/project.pbxproj b/dyld.xcodeproj/project.pbxproj index 2165020..504873c 100644 --- a/dyld.xcodeproj/project.pbxproj +++ b/dyld.xcodeproj/project.pbxproj @@ -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 */, @@ -66,12 +67,14 @@ 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 */; }; @@ -173,6 +176,13 @@ 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 */; @@ -267,15 +277,15 @@ 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 */ = { @@ -332,12 +342,12 @@ F9AB709D0BA75730002F6068 /* dyldLibSystemInterface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyldLibSystemInterface.h; path = src/dyldLibSystemInterface.h; sourceTree = ""; }; 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 = ""; }; - F9B0913811F11DAB00096D49 /* dsc_slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_slider.h; sourceTree = ""; }; + 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 = ""; }; F9CE30781208F1B50098B590 /* dsc_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_extractor.cpp; sourceTree = ""; }; F9CE30791208F1B50098B590 /* dsc_extractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_extractor.h; sourceTree = ""; }; + 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 = ""; }; + F9D49CCB1458B95200F86ADD /* start_glue.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = start_glue.s; path = src/start_glue.s; sourceTree = ""; }; F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = dlopen_preflight.3; sourceTree = ""; }; 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; }; @@ -380,6 +390,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F9D1001014D8D0BA00099D91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -442,8 +459,6 @@ 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 */, @@ -470,7 +485,7 @@ F93937320A94FAF700070A07 /* update_dyld_shared_cache */, F9F2A5590F7AEE9800B7C9EB /* libdsc.a */, F99B8E670FEC121100701838 /* dyld_shared_cache_util */, - F9B0912311F11D1600096D49 /* libdsc_slider.a */, + F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */, ); name = Products; sourceTree = ""; @@ -490,6 +505,7 @@ F9ED4CCD0630A7F100DF4E74 /* dyldLock.h */, F9ED4CCE0630A7F100DF4E74 /* dyldNew.cpp */, F9ED4CCF0630A7F100DF4E74 /* dyldStartup.s */, + F9D49CCB1458B95200F86ADD /* start_glue.s */, F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */, F9ED4CD00630A7F100DF4E74 /* glue.c */, F9ED4CD10630A7F100DF4E74 /* ImageLoader.cpp */, @@ -522,6 +538,7 @@ F939F219078F1A2100AC144F /* dyld_debug.h */, F9ED4CEA0630A80600DF4E74 /* dyld.h */, F99EE6AE06B48D4200BF1992 /* dlfcn.h */, + F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */, ); name = include; sourceTree = ""; @@ -536,6 +553,16 @@ }; /* 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; @@ -551,6 +578,7 @@ dependencies = ( F99B8EA00FEC195800701838 /* PBXTargetDependency */, F9CE330B120F40EA0098B590 /* PBXTargetDependency */, + F9D1004714D8D91100099D91 /* PBXTargetDependency */, ); name = update_dyld_shared_cache; productName = update_dyld_shared_cache; @@ -573,21 +601,22 @@ 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; @@ -650,8 +679,11 @@ /* 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 = ( @@ -672,7 +704,7 @@ F93937310A94FAF700070A07 /* update_dyld_shared_cache */, F9F2A5580F7AEE9800B7C9EB /* libdsc */, F99B8E550FEC10F600701838 /* dyld_shared_cache_util */, - F9B0912211F11D1600096D49 /* libdsc_slider */, + F9D1001114D8D0BA00099D91 /* dsc_extractor */, ); }; /* End PBXProject section */ @@ -705,7 +737,7 @@ ); 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 */ = { @@ -759,11 +791,12 @@ ); 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; }; @@ -798,6 +831,7 @@ F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */, F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */, F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */, + F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -843,6 +877,11 @@ target = F9F2A5580F7AEE9800B7C9EB /* libdsc */; targetProxy = F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */; }; + F9D1004714D8D91100099D91 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F9D1001114D8D0BA00099D91 /* dsc_extractor */; + targetProxy = F9D1004614D8D91100099D91 /* PBXContainerItemProxy */; + }; F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = F9ED4C970630A76000DF4E74 /* dyld */; @@ -872,7 +911,6 @@ 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; @@ -882,10 +920,10 @@ 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; @@ -896,7 +934,7 @@ 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"; }; @@ -906,16 +944,18 @@ 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; @@ -930,12 +970,10 @@ 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; @@ -948,37 +986,43 @@ 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; @@ -987,17 +1031,17 @@ 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; @@ -1024,12 +1068,10 @@ "$(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; @@ -1044,17 +1086,17 @@ 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"; @@ -1079,12 +1121,10 @@ "$(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; @@ -1109,7 +1149,6 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; HEADER_SEARCH_PATHS = "$(SRCROOT)/include"; INSTALL_PATH = /usr/lib/system; - PREBINDING = NO; PRODUCT_NAME = dyld; WARNING_CFLAGS = ( "-Wmost", @@ -1141,11 +1180,10 @@ 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; @@ -1175,12 +1213,14 @@ F9D8C7EA087B087300E93EFB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LIBRARY = "compiler-default"; }; name = Debug; }; F9D8C7EC087B087300E93EFB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_CXX_LIBRARY = "compiler-default"; }; name = Release; }; @@ -1190,13 +1230,11 @@ 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; @@ -1207,7 +1245,6 @@ 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; @@ -1256,11 +1293,11 @@ 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; diff --git a/include/mach-o/dyld_gdb.h b/include/mach-o/dyld_gdb.h index 04137ac..eaadf64 100644 --- a/include/mach-o/dyld_gdb.h +++ b/include/mach-o/dyld_gdb.h @@ -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 diff --git a/include/mach-o/dyld_priv.h b/include/mach-o/dyld_priv.h index b33c231..9464fb8 100644 --- a/include/mach-o/dyld_priv.h +++ b/include/mach-o/dyld_priv.h @@ -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 index 0000000..b7db57d --- /dev/null +++ b/include/objc-shared-cache.h @@ -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 +#include +#ifdef SELOPT_WRITE +#include +#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, eqstr> string_map; + +// class name => (class vmaddress, header_info vmaddress) +typedef __gnu_cxx::hash_multimap, __gnu_cxx::hash, 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 != 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 != coff) { + return "class offset too big (metadata not optimized)"; + } + if ((hoff<>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 + 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 != coff) { + return "class offset too big (metadata not optimized)"; + } + if ((hoff<>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= 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<>const3)); + 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; ib_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; qval_b */ + + if (q == 1) + break; /* don't do transitive closure */ + + for (i=0; ilist_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 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= 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< P; - -}; - struct x86 { typedef Pointer32 P; diff --git a/launch-cache/MachOBinder.hpp b/launch-cache/MachOBinder.hpp index ac882dc..332478f 100644 --- a/launch-cache/MachOBinder.hpp +++ b/launch-cache/MachOBinder.hpp @@ -97,7 +97,7 @@ private: void doBindDyldLazyInfo(std::vector& 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& pointersInData); pint_t resolveUndefined(const macho_nlist

* undefinedSymbol); bool findExportedSymbolAddress(const char* name, pint_t* result, Binder** foundIn, bool* isResolverSymbol); @@ -190,7 +190,7 @@ Binder::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress fDyldInfo = (macho_dyld_info_command

*)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::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress } } -template <> uint8_t Binder::pointerRelocSize() { return 2; } template <> uint8_t Binder::pointerRelocSize() { return 2; } template <> uint8_t Binder::pointerRelocSize() { return 3; } template <> uint8_t Binder::pointerRelocSize() { return 2; } -template <> uint8_t Binder::pointerRelocType() { return GENERIC_RELOC_VANILLA; } template <> uint8_t Binder::pointerRelocType() { return GENERIC_RELOC_VANILLA; } template <> uint8_t Binder::pointerRelocType() { return X86_64_RELOC_UNSIGNED; } template <> uint8_t Binder::pointerRelocType() { return ARM_RELOC_VANILLA; } @@ -363,8 +361,18 @@ void Binder::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::doSetUpDyldSection() template void Binder::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal, - int64_t addend, const char* symbolName, bool lazyPointer, std::vector& pointersInData) + int64_t addend, const char* symbolName, bool lazyPointer, bool weakImport, std::vector& pointersInData) { //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName); const std::vector& segments = this->fLayout.getSegments(); @@ -561,9 +569,16 @@ void Binder::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin pint_t targetSymbolAddress; bool isResolverSymbol; Binder* 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::doBindDyldLazyInfo(std::vector& 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::doBindDyldLazyInfo(std::vector& 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::doBindDyldLazyInfo(std::vector& 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::doBindDyldInfo(std::vector& 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::doBindDyldInfo(std::vector& 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::doBindDyldInfo(std::vector& 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; diff --git a/launch-cache/MachOFileAbstraction.hpp b/launch-cache/MachOFileAbstraction.hpp index 3be3fa2..6314caa 100644 --- a/launch-cache/MachOFileAbstraction.hpp +++ b/launch-cache/MachOFileAbstraction.hpp @@ -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

* getLoadCommand(int query) const + { + const macho_load_command

* cmds = (macho_load_command

*)((uint8_t*)this + sizeof(macho_header

)); + uint32_t cmd_count = this->ncmds(); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == query ) { + return cmd; + } + cmd = (macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); + } + return NULL; + } + typedef typename P::E E; private: macho_header_content

header; diff --git a/launch-cache/MachOLayout.hpp b/launch-cache/MachOLayout.hpp index e23cbac..4d6583b 100644 --- a/launch-cache/MachOLayout.hpp +++ b/launch-cache/MachOLayout.hpp @@ -364,9 +364,6 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set(&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(&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(&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::setmagic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) { - if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(mh->cputype), OSSwapBigToHostInt32(mh->cpusubtype)) ) - fLayouts.push_back(new MachOLayout(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(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::setcputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) fLayouts.push_back(new MachOLayout(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::MachOLayout(const void* machHeader, uint64_t offset, const char* } -template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_POWERPC; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_I386; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_X86_64; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_ARM; } -template <> -bool MachOLayout::isSplitSeg() const -{ - return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 ); -} - template <> bool MachOLayout::isSplitSeg() const { diff --git a/launch-cache/MachORebaser.hpp b/launch-cache/MachORebaser.hpp index 8907aad..88c4f83 100644 --- a/launch-cache/MachORebaser.hpp +++ b/launch-cache/MachORebaser.hpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -170,7 +169,6 @@ Rebaser::Rebaser(const MachOLayoutAbstraction& layout) fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides(); } -template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_POWERPC; } template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_I386; } template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_X86_64; } template <> cpu_type_t Rebaser::getArchitecture() const { return CPU_TYPE_ARM; } @@ -536,25 +534,103 @@ void Rebaser::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::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::doLocalRelocation(const macho_relocation_info* } } -template <> -void Rebaser::doLocalRelocation(const macho_relocation_info

* 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

* sreloc = (macho_scattered_relocation_info

*)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::doLocalRelocation(const macho_relocation_info

* 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(&p[fileOffset])); - break; case CPU_TYPE_I386: fRebasers.push_back(new Rebaser(&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(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(mh)); } else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) { diff --git a/launch-cache/ObjCLegacyAbstraction.hpp b/launch-cache/ObjCLegacyAbstraction.hpp index 43ab45a..19ee2d3 100644 --- a/launch-cache/ObjCLegacyAbstraction.hpp +++ b/launch-cache/ObjCLegacyAbstraction.hpp @@ -22,13 +22,21 @@ * @APPLE_LICENSE_HEADER_END@ */ +#define OBJC_IMAGE_SUPPORTS_GC (1<<1) +#define OBJC_IMAGE_REQUIRES_GC (1<<2) + template 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 @@ -221,14 +229,5 @@ public: uint64_t newValue = visitor.visit(oldValue); selrefs.set(s, newValue); } - - // Mark image_info - const macho_section

*imageInfoSection = - header->getSection("__OBJC", "__image_info"); - if (imageInfoSection) { - objc_image_info *info = (objc_image_info *) - cache->mappedAddressForVMAddress(imageInfoSection->addr()); - info->setSelectorsPrebound(); - } } }; diff --git a/launch-cache/ObjCModernAbstraction.hpp b/launch-cache/ObjCModernAbstraction.hpp index 9dc9b90..41419a8 100644 --- a/launch-cache/ObjCModernAbstraction.hpp +++ b/launch-cache/ObjCModernAbstraction.hpp @@ -22,6 +22,7 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include "MachOLayout.hpp" #include #include @@ -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 +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* cache, const macho_header

* mh) + : next(0), + mhdr(0), + info(0), + fname(0), + loaded(0), + allClassesRealized(0) + { + A::P::setP(mhdr, cache->VMAddressForMappedAddress(mh)); + const macho_section

* 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& pointersToAdd) { + pointersToAdd.push_back(&mhdr); + if (info) pointersToAdd.push_back(&info); + } + + uint64_t header_vmaddr() const { return mhdr; } +}; template class objc_method_list_t; // forward reference @@ -203,15 +242,30 @@ public: template 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 *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); } + + bool hasOffset() const { return A::P::getP(offset) != 0; } + pint_t getOffset(SharedCache *cache) const { return A::P::getP(*(pint_t * const)cache->mappedAddressForVMAddress(A::P::getP(offset))); } + void setOffset(SharedCache *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< class objc_ivar_list_t { + typedef typename A::P::uint_t pint_t; uint32_t entsize; uint32_t count; objc_ivar_t first; @@ -228,7 +282,7 @@ public: uint32_t getEntsize() const { return A::P::E::get32(entsize); } - objc_ivar_t& get(typename A::P::pint_t i) const { return *(objc_ivar_t *)((uint8_t *)&first + i * A::P::E::get32(entsize)); } + objc_ivar_t& get(pint_t i) const { return *(objc_ivar_t *)((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 *getMethodList(SharedCache* cache) const { return (objc_method_list_t *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); } objc_protocol_list_t *getProtocolList(SharedCache* cache) const { return (objc_protocol_list_t *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); } + objc_ivar_list_t *getIvarList(SharedCache* cache) const { return (objc_ivar_list_t *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); } + objc_property_list_t *getPropertyList(SharedCache* cache) const { return (objc_property_list_t *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); } const char * getName(SharedCache* 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* cache) const { return getData(cache)->isMetaClass(); } + objc_class_t *getIsa(SharedCache *cache) const { return (objc_class_t *)cache->mappedAddressForVMAddress(A::P::getP(isa)); } + objc_class_t *getSuperclass(SharedCache *cache) const { return (objc_class_t *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); } + objc_class_data_t *getData(SharedCache* cache) const { return (objc_class_data_t *)cache->mappedAddressForVMAddress(A::P::getP(data)); } objc_method_list_t *getMethodList(SharedCache* 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 +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* cache, const macho_header

* header, objc_class_t *cls) + { + objc_class_data_t *data = cls->getData(cache); + objc_ivar_list_t *ivars = data->getIvarList(cache); + if (ivars) { + for (pint_t i = 0; i < ivars->getCount(); i++) { + objc_ivar_t& 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* cache, const macho_header

* header, objc_class_t *cls) + { + walk(cache, header, cls); + } +}; + +// Call visitor.visitClass() on every class. +template +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* cache, const macho_header

* header) + { + PointerSection *> + classes(cache, header, "__DATA", "__objc_classlist"); + + for (pint_t i = 0; i < classes.count(); i++) { + objc_class_t *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 @@ -584,7 +706,7 @@ public: MethodListWalker(V& visitor) : mVisitor(visitor) { } - void walk(SharedCache* cache, const macho_header

* header) + void walk(SharedCache* cache, const macho_header

* header, bool walkProtocols) { // Method lists in classes PointerSection *> @@ -615,25 +737,27 @@ public: } } - // Method description lists from protocols - PointerSection *> - protocols(cache, header, "__DATA", "__objc_protolist"); - for (pint_t i = 0; i < protocols.count(); i++) { - objc_protocol_t *proto = protocols.get(i); - objc_method_list_t *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 *> + protocols(cache, header, "__DATA", "__objc_protolist"); + for (pint_t i = 0; i < protocols.count(); i++) { + objc_protocol_t *proto = protocols.get(i); + objc_method_list_t *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 > mw(*this); - mw.walk(cache, header); + mw.walk(cache, header, true); // @selector references PointerSection @@ -687,14 +811,96 @@ public: pint_t newValue = mVisitor.visit(oldValue); msg.setName(newValue); } + } +}; - // Mark image_info - const macho_section

*imageInfoSection = - header->getSection("__DATA", "__objc_imageinfo"); + +// Update selector references. The visitor performs recording and uniquing. +template +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* cache, const macho_header

* /*unused, may be NULL*/, objc_class_t *cls, objc_ivar_t *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* cache, const macho_header

* /*unused, may be NULL*/, objc_class_t *cls) + { + objc_class_t *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 *data = cls->getData(cache); + objc_class_data_t *super_data = super->getData(cache); + int32_t diff = super_data->getInstanceSize() - data->getInstanceStart(); + if (diff > 0) { + IvarWalker > 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* cache, const macho_header

* header) + { + // The slide code cannot fix up GC layout strings so skip modules that support ore require GC + const macho_section

*imageInfoSection = header->getSection("__DATA", "__objc_imageinfo"); if (imageInfoSection) { - objc_image_info *info = (objc_image_info *) - cache->mappedAddressForVMAddress(imageInfoSection->addr()); - info->setSelectorsPrebound(); + objc_image_info *info = (objc_image_info *)cache->mappedAddressForVMAddress(imageInfoSection->addr()); + if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) { + ClassWalker > 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 >; void visitMethodList(objc_method_list_t *mlist) { typename objc_method_t::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* cache, macho_header

* header) { MethodListWalker > 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 -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* fHinfos; + size_t fCount; - bool segmentContainsPointer(SharedCache* cache, - const macho_segment_command

* 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* cache, - macho_header

* 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)ptr); - } - }; - - typedef std::deque*> CategoryList; - typedef std::vector CategoryRefs; - - struct ClassChanges { - CategoryList categories; - CategoryRefs catrefs; - - objc_method_list_t* instanceMethods; - objc_method_list_t* classMethods; - objc_protocol_list_t* protocols; - objc_property_list_t* 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*, ClassChanges, pointer_hash> ClassMap; - - class RangeArray { - typedef std::pair Range; - std::deque 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)) { + return "libobjc's read/write section is too small (metadata not optimized)"; } - void add(const Range& r) { - // find insertion point - std::deque::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::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::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::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)); + fHinfos = (objc_header_info_t*)(buf32+2); - return result; - } - }; + size_t total = sizeof(uint32_t) + count*sizeof(objc_header_info_t); + buf += total; + bufSize -= total; - void copyMethods(typename objc_method_list_t::method_iterator& dst, - const objc_method_list_t* srcList) - { - objc_method_list_t::method_iterator:: - overwrite(dst, srcList); + return NULL; } - void copyProperties(typename objc_property_list_t::property_iterator& dst, - const objc_property_list_t* srcList) - { - objc_property_list_t::property_iterator:: - overwrite(dst, srcList); + void update(SharedCache* cache, const macho_header

* mh, std::vector& pointersInData) + { + objc_header_info_t* hi = new(&fHinfos[fCount++]) objc_header_info_t(cache, mh); + hi->addPointers(pointersInData); } - void copyProtocols(objc_protocol_list_t* dst, pint_t& dstIndex, - const objc_protocol_list_t* src) + objc_header_info_t* hinfoForHeader(SharedCache* cache, const macho_header

* mh) { - dst->overwrite(dstIndex, src); - } - - class InSet - { - public: - InSet(std::set& deadPointers) : _deadPointers(deadPointers) {} - - bool operator()(void* ptr) const { - return ( _deadPointers.count(ptr) != 0 ); - } - - private: - std::set& _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* cache, macho_header

* header, std::vector& pointersInData) - { - // Build class=>cateories mapping. - // Disregard target classes that aren't in this binary. - - ClassMap map; - - PointerSection *> - nlcatsect(cache, header, "__DATA", "__objc_nlcatlist"); - PointerSection *> - catsect(cache, header, "__DATA", "__objc_catlist"); - for (pint_t i = 0; i < catsect.count(); i++) { - objc_category_t *cat = catsect.get(i); - objc_class_t *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 pointersToRemove; - for (typename ClassMap::iterator i = map.begin(); - i != map.end(); - ++i) - { - objc_class_t* cls = i->first; - objc_class_t* 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* mlist; - objc_property_list_t* proplist; - objc_protocol_list_t* 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* 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::newMethodList(instanceMethodsCount, methodEntsize); - reserve = P::round_up(reserve + changes.instanceMethods->byteSize()); - } - if (addedClassMethods) { - changes.classMethods = objc_method_list_t::newMethodList(classMethodsCount, methodEntsize); - reserve = P::round_up(reserve + changes.classMethods->byteSize()); - } - if (addedInstanceProperties) { - changes.instanceProperties = objc_property_list_t::newPropertyList(instancePropertyCount, propertyEntsize); - reserve = P::round_up(reserve + changes.instanceProperties->byteSize()); - } - if (addedProtocols) { - changes.protocols = objc_protocol_list_t::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::method_iterator newInstanceMethods; - typename objc_method_list_t::method_iterator newClassMethods; - typename objc_property_list_t::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* 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* 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* cls = i->first; - objc_class_t* 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::addPointers(bytes, pointersInData); - cls->setMethodList(cache, (objc_method_list_t *)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::addPointers(bytes, pointersInData); - meta->setMethodList(cache, (objc_method_list_t *)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::addPointers(bytes, pointersInData); - cls->setPropertyList(cache, (objc_property_list_t *)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 *)bytes); - objc_protocol_list_t::addPointers(bytes, pointersInData); - cls->addProtocolListPointer(cache, pointersInData); - meta->setProtocolList(cache, (objc_protocol_list_t *)bytes); - meta->addProtocolListPointer(cache, pointersInData); - } - - // Disavow all knowledge of the categories. - - for (typename CategoryRefs::iterator j = changes.catrefs.begin(); - j != changes.catrefs.end(); - ++j) - { - catsect.set(*j, 0); - } - - mCategoriesAttached += changes.categories.size(); - } - - catsect.removeNulls(); - return NULL; } - - ssize_t bytesUsed() { return mBytesUsed; } }; diff --git a/launch-cache/dsc_extractor.cpp b/launch-cache/dsc_extractor.cpp index b86b366..c94cbe0 100644 --- a/launch-cache/dsc_extractor.cpp +++ b/launch-cache/dsc_extractor.cpp @@ -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* mh, const void* mapped_cache, macho_segment_command

* linkEditSegCmd = NULL; macho_symtab_command

* symtab = NULL; macho_dysymtab_command

* dynamicSymTab = NULL; + macho_linkedit_data_command

* functionStarts = NULL; + macho_linkedit_data_command

* dataInCode = NULL; for (uint32_t i = 0; i < cmd_count; ++i) { if ( cmd->cmd() == macho_segment_command

::CMD ) { // update segment/section file offsets @@ -121,6 +123,12 @@ int optimize_linkedit(macho_header* mh, const void* mapped_cache, else if ( cmd->cmd() == LC_DYSYMTAB ) { dynamicSymTab = (macho_dysymtab_command

*)cmd; } + else if ( cmd->cmd() == LC_FUNCTION_STARTS ) { + functionStarts = (macho_linkedit_data_command

*)cmd; + } + else if ( cmd->cmd() == LC_DATA_IN_CODE ) { + dataInCode = (macho_linkedit_data_command

*)cmd; + } cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); } @@ -137,8 +145,23 @@ int optimize_linkedit(macho_header* 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

); const uint32_t newStringPoolOffset = newIndSymTabOffset + dynamicSymTab->nindirectsyms()*sizeof(uint32_t); macho_nlist

* const newSymTabStart = (macho_nlist

*)(((uint8_t*)mh) + newSymTabOffset); @@ -165,6 +188,14 @@ int optimize_linkedit(macho_header* 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 &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; else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64") == 0 ) dylib_create_func = dylib_maker; - else if ( strcmp((char*)mapped_cache, "dyld_v1 ppc") == 0 ) - dylib_create_func = dylib_maker; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv5") == 0 ) dylib_create_func = dylib_maker; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv6") == 0 ) dylib_create_func = dylib_maker; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7") == 0 ) dylib_create_func = dylib_maker; + else if ( strncmp((char*)mapped_cache, "dyld_v1 armv7", 14) == 0 ) + dylib_create_func = dylib_maker; 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 \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 - + + diff --git a/launch-cache/dsc_iterator.cpp b/launch-cache/dsc_iterator.cpp index 9b5cac4..50ff8c9 100644 --- a/launch-cache/dsc_iterator.cpp +++ b/launch-cache/dsc_iterator.cpp @@ -125,14 +125,14 @@ int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, return dyld::walkImages(cache, callback); else if ( strcmp((char*)cache, "dyld_v1 x86_64") == 0 ) return dyld::walkImages(cache, callback); - else if ( strcmp((char*)cache, "dyld_v1 ppc") == 0 ) - return dyld::walkImages(cache, callback); else if ( strcmp((char*)cache, "dyld_v1 armv5") == 0 ) return dyld::walkImages(cache, callback); else if ( strcmp((char*)cache, "dyld_v1 armv6") == 0 ) return dyld::walkImages(cache, callback); else if ( strcmp((char*)cache, "dyld_v1 armv7") == 0 ) return dyld::walkImages(cache, callback); + else if ( strncmp((char*)cache, "dyld_v1 armv7", 14) == 0 ) + return dyld::walkImages(cache, callback); else return -1; } diff --git a/launch-cache/dsc_slider.cpp b/launch-cache/dsc_slider.cpp deleted file mode 100644 index d11f46a..0000000 --- a/launch-cache/dsc_slider.cpp +++ /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 -#include -#include -#include -#include -#include -#include - -#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/dyld_cache_format.h b/launch-cache/dyld_cache_format.h index 42a1a13..70d897c 100644 --- a/launch-cache/dyld_cache_format.h +++ b/launch-cache/dyld_cache_format.h @@ -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 diff --git a/launch-cache/dyld_shared_cache_util.cpp b/launch-cache/dyld_shared_cache_util.cpp index d82674a..b0b6918 100644 --- a/launch-cache/dyld_shared_cache_util.cpp +++ b/launch-cache/dyld_shared_cache_util.cpp @@ -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* header = (dyldCacheHeader*)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; else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64") == 0 ) callback = segment_callback; - else if ( strcmp((char*)mapped_cache, "dyld_v1 ppc") == 0 ) - callback = segment_callback; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv5") == 0 ) callback = segment_callback; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv6") == 0 ) callback = segment_callback; else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7") == 0 ) callback = segment_callback; + else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7f") == 0 ) + callback = segment_callback; + else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7k") == 0 ) + callback = segment_callback; else { fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n"); exit(1); diff --git a/launch-cache/update_dyld_shared_cache.cpp b/launch-cache/update_dyld_shared_cache.cpp index c7a3874..ac9cc1c 100644 --- a/launch-cache/update_dyld_shared_cache.cpp +++ b/launch-cache/update_dyld_shared_cache.cpp @@ -59,9 +59,9 @@ #include "CacheFileAbstraction.hpp" #define SELOPT_WRITE -#include +#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& 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 fgPerArchGraph; static const char* fgFileSystemRoot; - static bool fgUsesOverlay; + static const char* fgFileSystemOverlay; ArchPair fArchPair; std::set fRoots; @@ -161,7 +162,7 @@ private: }; std::map 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& 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::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 { - // 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 { + // 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)]; } + // 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 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::arch() { return CPU_TYPE_POWERPC; } template <> cpu_type_t SharedCache::arch() { return CPU_TYPE_I386; } template <> cpu_type_t SharedCache::arch() { return CPU_TYPE_X86_64; } template <> cpu_type_t SharedCache::arch() { return CPU_TYPE_ARM; } -template <> uint64_t SharedCache::sharedRegionReadOnlyStartAddress() { return 0x90000000; } template <> uint64_t SharedCache::sharedRegionReadOnlyStartAddress() { return 0x90000000; } template <> uint64_t SharedCache::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; } template <> uint64_t SharedCache::sharedRegionReadOnlyStartAddress() { return 0x30000000; } -template <> uint64_t SharedCache::sharedRegionWritableStartAddress() { return 0xA0000000; } template <> uint64_t SharedCache::sharedRegionWritableStartAddress() { return 0xAC000000; } template <> uint64_t SharedCache::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; } template <> uint64_t SharedCache::sharedRegionWritableStartAddress() { return 0x3E000000; } -template <> uint64_t SharedCache::sharedRegionReadOnlySize() { return 0x10000000; } template <> uint64_t SharedCache::sharedRegionReadOnlySize() { return 0x1C000000; } template <> uint64_t SharedCache::sharedRegionReadOnlySize() { return 0x40000000; } template <> uint64_t SharedCache::sharedRegionReadOnlySize() { return 0x0E000000; } -template <> uint64_t SharedCache::sharedRegionWritableSize() { return 0x10000000; } template <> uint64_t SharedCache::sharedRegionWritableSize() { return 0x04000000; } template <> uint64_t SharedCache::sharedRegionWritableSize() { return 0x10000000; } template <> uint64_t SharedCache::sharedRegionWritableSize() { return 0x02000000; } -template <> const char* SharedCache::archName() { return "ppc"; } template <> const char* SharedCache::archName() { return "i386"; } template <> const char* SharedCache::archName() { return "x86_64"; } template <> const char* SharedCache::archName() { return "arm"; } -template <> const char* SharedCache::cacheFileSuffix(bool optimized, const char*) { return optimized ? "ppc" : "rosetta"; } template <> const char* SharedCache::cacheFileSuffix(bool, const char* archName) { return archName; } template <> const char* SharedCache::cacheFileSuffix(bool, const char* archName){ return archName; } template <> const char* SharedCache::cacheFileSuffix(bool, const char* archName) { return archName; } template -SharedCache::SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress) +SharedCache::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::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::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::getWritableSegmentNewAddress(uint64_t proposedNewAddres return proposedNewAddress; } -template <> -uint64_t SharedCache::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 void SharedCache::assignNewBaseAddresses(bool verify) @@ -1012,7 +1047,6 @@ void SharedCache::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::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

* fDyldInfo; macho_dysymtab_command

* fDynamicSymbolTable; macho_linkedit_data_command

* fFunctionStarts; + macho_linkedit_data_command

* fDataInCode; macho_symtab_command

* fSymbolTableLoadCommand; const macho_nlist

* 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 LinkEditOptimizer::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache& 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::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

*)fLayout.getSegments()[0].mappedAddress(); @@ -1497,6 +1535,8 @@ LinkEditOptimizer::LinkEditOptimizer(const MachOLayoutAbstraction& layout, co break; case LC_FUNCTION_STARTS: fFunctionStarts = (macho_linkedit_data_command

*)cmd; + case LC_DATA_IN_CODE: + fDataInCode = (macho_linkedit_data_command

*)cmd; break; } cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); @@ -1674,6 +1714,17 @@ void LinkEditOptimizer::copyFunctionStarts(uint32_t& offset) } } +template +void LinkEditOptimizer::copyDataInCode(uint32_t& offset) +{ + if ( fDataInCode != NULL ) { + fDataInCodeOffsetInNewLinkEdit = offset; + memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fDataInCode->dataoff()], fDataInCode->datasize()); + offset += fDataInCode->datasize(); + } +} + + template void LinkEditOptimizer::copyIndirectSymbolTable(uint32_t& offset) { @@ -1772,6 +1823,10 @@ void LinkEditOptimizer::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

* srcCmd = cmds; @@ -1781,6 +1836,7 @@ void LinkEditOptimizer::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::optimizeLINKEDIT(bool keepSignatures) } fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit; + // copy data-in-code info + fOffsetOfDataInCodeInCombinedLinkedit = offset; + for(typename std::vector*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) { + (*it)->copyDataInCode(offset); + } + fSizeOfDataInCodeInCombinedLinkedit = offset - fOffsetOfDataInCodeInCombinedLinkedit; + // copy indirect symbol tables fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset; for(typename std::vector*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) { @@ -1932,7 +1995,6 @@ uint8_t* SharedCache::optimizeLINKEDIT(bool keepSignatures) } - template class ObjCSelectorUniquer { @@ -1966,16 +2028,73 @@ public: size_t count() const { return fCount; } }; + +template +class ClassListBuilder +{ +private: + typedef typename A::P P; + + objc_opt::string_map fClassNames; + objc_opt::class_map fClasses; + size_t fCount; + HeaderInfoOptimizer& fHinfos; + +public: + + ClassListBuilder(HeaderInfoOptimizer& hinfos) + : fClassNames() + , fClasses() + , fCount(0) + , fHinfos(hinfos) + { } + + void visitClass(SharedCache* cache, + const macho_header

* header, + objc_class_t* 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(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 void SharedCache::optimizeObjC(std::vector& 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

*optROSection = NULL; const macho_section

*optRWSection = NULL; @@ -1983,9 +2102,6 @@ void SharedCache::optimizeObjC(std::vector& pointersInData) if ( strstr(it->layout->getFilePath(), "libobjc") != NULL ) { const macho_header

* mh = (const macho_header

*)(*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::optimizeObjC(std::vector& 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 objcDylibs; + for(typename std::vector::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) { + macho_header

*mh = (macho_header

*)(*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 addressSortedDylibs = objcDylibs; + std::sort(addressSortedDylibs.begin(), addressSortedDylibs.end(), ByAddressSorter()); + + uint64_t hinfoVMAddr = optRWSection->addr() + optRWSection->size() - optRWRemaining; + HeaderInfoOptimizer hinfoOptimizer; + err = hinfoOptimizer.init(objcDylibs.size(), optRWData, optRWRemaining); + if (err) { + warn(archName(), err); + return; + } + for(typename std::vector::const_iterator it = addressSortedDylibs.begin(); it != addressSortedDylibs.end(); ++it) { + const macho_header

*mh = (const macho_header

*)(*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::optimizeObjC(std::vector& pointersInData) // Heuristic: choose selectors from libraries with more cstring data first. // This tries to localize selector cstring memory. ObjCSelectorUniquer uniq(this); - std::vector sortedDylibs = fDylibs; - std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter()); + std::vector sizeSortedDylibs = objcDylibs; + std::sort(sizeSortedDylibs.begin(), sizeSortedDylibs.end(), ByCStringSectionSizeSorter()); SelectorOptimizer > selOptimizer(uniq); - for(typename std::vector::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) { + for(typename std::vector::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) { const macho_header

*mh = (const macho_header

*)(*it->layout).getSegments()[0].mappedAddress(); LegacySelectorUpdater >::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 classes(hinfoOptimizer); + ClassWalker< A, ClassListBuilder > classWalker(classes); + for(typename std::vector::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) { + const macho_header

*mh = (const macho_header

*)(*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 methodSorter; + for(typename std::vector::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) { + macho_header

*mh = (macho_header

*)(*it->layout).getSegments()[0].mappedAddress(); + methodSorter.optimize(this, mh); + } + + + // Repair ivar offsets. + + // This is SAFE: the runtime always validates ivar offsets at runtime. + + IvarOffsetOptimizer ivarOffsetOptimizer; + for(typename std::vector::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) { + const macho_header

*mh = (const macho_header

*)(*it->layout).getSegments()[0].mappedAddress(); + ivarOffsetOptimizer.optimize(this, mh); + } + + + // Success. Mark dylibs as optimized. + for(typename std::vector::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) { + const macho_header

*mh = (const macho_header

*)(*it->layout).getSegments()[0].mappedAddress(); + const macho_section

*imageInfoSection; + imageInfoSection = mh->getSection("__DATA", "__objc_imageinfo"); + if (!imageInfoSection) { + imageInfoSection = mh->getSection("__OBJC", "__image_info"); + } + if (imageInfoSection) { + objc_image_info *info = (objc_image_info *) + 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 categoryAttacher(categoryData, optRWSection->size() - categoryOffset); - for(typename std::vector::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) { - macho_header

*mh = (macho_header

*)(*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 methodSorter; - for(typename std::vector::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) { - macho_header

*mh = (macho_header

*)(*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::addCacheSlideInfo(){ return true; } template <> bool SharedCache::addCacheSlideInfo() { return true; } template <> bool SharedCache::addCacheSlideInfo() { return false; } -template <> bool SharedCache::addCacheSlideInfo() { return false; } template -bool SharedCache::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex, +bool SharedCache::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex, int archCount, bool keepSignatures) { bool didUpdate = false; @@ -2243,7 +2429,7 @@ bool SharedCache::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& segs = it->layout->getSegments(); for (int i=0; i < segs.size(); ++i) { @@ -2556,7 +2742,7 @@ bool SharedCache::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::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::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& paths -static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::set& onlyArchs, std::vector rootsPaths) +static void setSharedDylibs(const char* rootPath, const char* overlayPath, const std::set& onlyArchs, std::vector rootsPaths) { // set file system root - ArchGraph::setFileSystemRoot(rootPath, usesOverlay); + ArchGraph::setFileSystemRoot(rootPath); + ArchGraph::setFileSystemOverlay(overlayPath); // initialize all architectures requested for(std::set::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& onlyArchs) +static void scanForSharedDylibs(const char* rootPath, const char* overlayPath, const char* dirOfPathFiles, const std::set& 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& onlyArchs) +static void setSharedDylibs(const char* rootPath, const char* overlayPath, const char* pathsFile, const std::set& onlyArchs) { std::vector 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& onlyArchs, +static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, const std::set& 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__ - // Rosetta does not work with optimized dyld shared cache - SharedCache cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, false, usesOverlay, dyldBaseAddress); - didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures); - #else - SharedCache 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 cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress); - didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures); + SharedCache 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 cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress); - didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures); + SharedCache 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 cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress); - didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures); + SharedCache 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 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) { diff --git a/src/ImageLoader.cpp b/src/ImageLoader.cpp index 3b0e824..58b2282 100644 --- a/src/ImageLoader.cpp +++ b/src/ImageLoader.cpp @@ -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 ) { + // 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 + // initialize any upward depedencies + if ( hasUpwards ) { + for(unsigned int i=0; i < libraryCount(); ++i) { + ImageLoader* dependentImage = libImage(i); + // 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); diff --git a/src/ImageLoader.h b/src/ImageLoader.h index 582e60c..83bc1fe 100644 --- a/src/ImageLoader.h +++ b/src/ImageLoader.h @@ -56,12 +56,6 @@ #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 @@ -74,13 +68,22 @@ #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& 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_

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; diff --git a/src/ImageLoaderMachO.cpp b/src/ImageLoaderMachO.cpp index b068b7a..3a8ad7d 100644 --- a/src/ImageLoaderMachO.cpp +++ b/src/ImageLoaderMachO.cpp @@ -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 + // 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); - // 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; // verify that replacement is in this image - if ( (tuple.replacement >= textStart) && (tuple.replacement < textEnd) ) { + if ( this->containsAddress((void*)tuple.replacement) ) { for (std::vector::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); + // 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 + // 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. + // 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 - // 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 - // 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 + // 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 - // 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 - // 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()); + // 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]; + // 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()); - // 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; - // 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. diff --git a/src/ImageLoaderMachO.h b/src/ImageLoaderMachO.h index a2b657a..c3e192b 100644 --- a/src/ImageLoaderMachO.h +++ b/src/ImageLoaderMachO.h @@ -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; // Loading MH_DYLIB_STUB causing coalescable miscount diff --git a/src/ImageLoaderMachOClassic.cpp b/src/ImageLoaderMachOClassic.cpp index 33b055d..2d0cf1b 100644 --- a/src/ImageLoaderMachOClassic.cpp +++ b/src/ImageLoaderMachOClassic.cpp @@ -44,9 +44,6 @@ #include #include -#if __ppc__ || __ppc64__ - #include -#endif #if __x86_64__ #include #endif @@ -57,14 +54,6 @@ #include "ImageLoaderMachOClassic.h" #include "mach-o/dyld_images.h" -// optimize strcmp for ppc -#if __ppc__ - #include -#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__ diff --git a/src/ImageLoaderMachOCompressed.cpp b/src/ImageLoaderMachOCompressed.cpp index dda3e8a..2d0cca2 100644 --- a/src/ImageLoaderMachOCompressed.cpp +++ b/src/ImageLoaderMachOCompressed.cpp @@ -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 + // interposing dylibs have the stub address as their replacee + for (std::vector::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)(); diff --git a/src/dyld.cpp b/src/dyld.cpp index 31265a9..6854ef5 100644 --- a/src/dyld.cpp +++ b/src/dyld.cpp @@ -56,6 +56,15 @@ #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 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 sAllImages; static std::vector 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& 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::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::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::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* handlers = stateToHandlers(state, sSingleHandlers); if ( handlers != NULL ) { - handlers->push_back(handler); + // 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::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 = ®isterDOFs; 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::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; } + + +// 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(); diff --git a/src/dyld.h b/src/dyld.h index 9ad1ef8..19b4431 100644 --- a/src/dyld.h +++ b/src/dyld.h @@ -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(); diff --git a/src/dyldAPIs.cpp b/src/dyldAPIs.cpp index 0d0dbc7..d001184 100644 --- a/src/dyldAPIs.cpp +++ b/src/dyldAPIs.cpp @@ -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__ - // 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; } diff --git a/src/dyldAPIsInLibSystem.cpp b/src/dyldAPIsInLibSystem.cpp index cb99cdd..0417585 100644 --- a/src/dyldAPIsInLibSystem.cpp +++ b/src/dyldAPIsInLibSystem.cpp @@ -37,11 +37,28 @@ 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}; // diff --git a/src/dyldExceptions.c b/src/dyldExceptions.c index cff7dbe..2520f8f 100644 --- a/src/dyldExceptions.c +++ b/src/dyldExceptions.c @@ -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; diff --git a/src/dyldInitialization.cpp b/src/dyldInitialization.cpp index e40b1e8..a1266d7 100644 --- a/src/dyldInitialization.cpp +++ b/src/dyldInitialization.cpp @@ -31,9 +31,6 @@ #include #include #include -#if __ppc__ || __ppc64__ - #include -#endif #if __x86_64__ #include #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); } diff --git a/src/dyldLibSystemGlue.c b/src/dyldLibSystemGlue.c index bbd8b01..0fdda05 100644 --- a/src/dyldLibSystemGlue.c +++ b/src/dyldLibSystemGlue.c @@ -23,11 +23,20 @@ */ #include +#include // // 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 @@ -35,9 +44,19 @@ // 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 // @@ -54,5 +73,3 @@ int _dyld_func_lookup(const char* dyld_func_name, void **address) } - - diff --git a/src/dyldLibSystemInterface.h b/src/dyldLibSystemInterface.h index 874c497..9a5fd60 100644 --- a/src/dyldLibSystemInterface.h +++ b/src/dyldLibSystemInterface.h @@ -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 }; diff --git a/src/dyldStartup.s b/src/dyldStartup.s index cf296ef..11c8f1f 100644 --- a/src/dyldStartup.s +++ b/src/dyldStartup.s @@ -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 - - .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__ diff --git a/src/dyld_debug.c b/src/dyld_debug.c index 9db993f..8132b2c 100644 --- a/src/dyld_debug.c +++ b/src/dyld_debug.c @@ -24,228 +24,3 @@ int dummy_dyld_symbol = 1; -#include - -// 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 diff --git a/src/glue.c b/src/glue.c index 9f65555..9ccc656 100644 --- a/src/glue.c +++ b/src/glue.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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 index 0000000..4ccfd39 --- /dev/null +++ b/src/start_glue.s @@ -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 # 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 # 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 // backtraces of LC_MAIN binaries don't end in "start" +_start: + bl _exit // result in r0 already in param reg r0 + trap + +#endif /* __arm__ */ + diff --git a/src/stub_binding_helper.s b/src/stub_binding_helper.s index aec491f..8433475 100644 --- a/src/stub_binding_helper.s +++ b/src/stub_binding_helper.s @@ -180,71 +180,6 @@ _stub_binding_helper_interface: #endif -#if __ppc__ || __ppc64__ -#include -/* - * 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: diff --git a/unit-tests/build-iPhoneOS-unit-tests b/unit-tests/build-iPhoneOS-unit-tests index 21415cd..d6d19fc 100755 --- a/unit-tests/build-iPhoneOS-unit-tests +++ b/unit-tests/build-iPhoneOS-unit-tests @@ -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} diff --git a/unit-tests/include/common.makefile b/unit-tests/include/common.makefile index 461ebb0..ba256c8 100644 --- a/unit-tests/include/common.makefile +++ b/unit-tests/include/common.makefile @@ -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 diff --git a/unit-tests/run-all-unit-tests b/unit-tests/run-all-unit-tests index 91659ba..ceb2106 100755 --- a/unit-tests/run-all-unit-tests +++ b/unit-tests/run-all-unit-tests @@ -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 * * *" diff --git a/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c b/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c index a903b04..224d93e 100644 --- a/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c +++ b/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c @@ -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; diff --git a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile index 36bf14e..5c0374b 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile +++ b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile @@ -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 diff --git a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c index a903b04..2815ba1 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c +++ b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c @@ -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; } diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile index 2be1439..788e74a 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile +++ b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile @@ -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 diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c index a903b04..224d93e 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c +++ b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c @@ -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; diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c index a903b04..224d93e 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c +++ b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c @@ -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; diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c index a903b04..224d93e 100644 --- a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c +++ b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c @@ -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; diff --git a/unit-tests/test-cases/addend/main.c b/unit-tests/test-cases/addend/main.c index 006adaa..72b3710 100644 --- a/unit-tests/test-cases/addend/main.c +++ b/unit-tests/test-cases/addend/main.c @@ -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; } diff --git a/unit-tests/test-cases/bundle-memory-load-fat/Makefile b/unit-tests/test-cases/bundle-memory-load-fat/Makefile index 687eea6..e87cda5 100644 --- a/unit-tests/test-cases/bundle-memory-load-fat/Makefile +++ b/unit-tests/test-cases/bundle-memory-load-fat/Makefile @@ -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 diff --git a/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c b/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c index 938ea75..56690a7 100644 --- a/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c +++ b/unit-tests/test-cases/bundle-unload-keep-mapped/bundle.c @@ -28,5 +28,5 @@ static int mydata[10]; bool checkdata() { - return ( mydata[10] == 0 ); + return ( mydata[9] == 0 ); } diff --git a/unit-tests/test-cases/crt-apple/Makefile b/unit-tests/test-cases/crt-apple/Makefile index 78e43d5..bc160be 100644 --- a/unit-tests/test-cases/crt-apple/Makefile +++ b/unit-tests/test-cases/crt-apple/Makefile @@ -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 diff --git a/unit-tests/test-cases/crt-apple/main.c b/unit-tests/test-cases/crt-apple/main.c index 0d888ad..8a56fd8 100644 --- a/unit-tests/test-cases/crt-apple/main.c +++ b/unit-tests/test-cases/crt-apple/main.c @@ -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; } diff --git a/unit-tests/test-cases/crt-custom/Makefile b/unit-tests/test-cases/crt-custom/Makefile index ee12f10..7bb8ddc 100644 --- a/unit-tests/test-cases/crt-custom/Makefile +++ b/unit-tests/test-cases/crt-custom/Makefile @@ -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: diff --git a/unit-tests/test-cases/crt-custom/mystart.s b/unit-tests/test-cases/crt-custom/mystart.s index a95e0b5..c507706 100644 --- a/unit-tests/test-cases/crt-custom/mystart.s +++ b/unit-tests/test-cases/crt-custom/mystart.s @@ -6,6 +6,7 @@ .text + .align 2 .globl _mystart _mystart: #if __i386__ diff --git a/unit-tests/test-cases/dyld-slide/Makefile b/unit-tests/test-cases/dlopen_preflight-cycle/Makefile similarity index 59% rename from unit-tests/test-cases/dyld-slide/Makefile rename to unit-tests/test-cases/dlopen_preflight-cycle/Makefile index aa3debf..2123b40 100644 --- a/unit-tests/test-cases/dyld-slide/Makefile +++ b/unit-tests/test-cases/dlopen_preflight-cycle/Makefile @@ -1,5 +1,5 @@ ## -# Copyright (c) 2005-2009 Apple Inc. All rights reserved. +# Copyright (c) 2011 Apple Inc. All rights reserved. # # @APPLE_LICENSE_HEADER_START@ # @@ -23,35 +23,19 @@ 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 + ./main all: - ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,${STACK_SIZE} + ${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 + ${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 index 0000000..63c34e0 --- /dev/null +++ b/unit-tests/test-cases/dlopen_preflight-cycle/bar.c @@ -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 index 0000000..256a0e3 --- /dev/null +++ b/unit-tests/test-cases/dlopen_preflight-cycle/baz.c @@ -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 index 0000000..6924ac6 --- /dev/null +++ b/unit-tests/test-cases/dlopen_preflight-cycle/foo.c @@ -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 index 0000000..af5caec --- /dev/null +++ b/unit-tests/test-cases/dlopen_preflight-cycle/main.c @@ -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 // fprintf(), NULL +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include +#include +#include + +#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/fallback-non-unique-leaf-names/main.c b/unit-tests/test-cases/fallback-non-unique-leaf-names/main.c index f0ea779..351769a 100644 --- a/unit-tests/test-cases/fallback-non-unique-leaf-names/main.c +++ b/unit-tests/test-cases/fallback-non-unique-leaf-names/main.c @@ -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 index 0000000..56dd654 --- /dev/null +++ b/unit-tests/test-cases/image-state-deny-all_image_infos/Makefile @@ -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 index 0000000..e425999 --- /dev/null +++ b/unit-tests/test-cases/image-state-deny-all_image_infos/bar.c @@ -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 index 0000000..ed4b56c --- /dev/null +++ b/unit-tests/test-cases/image-state-deny-all_image_infos/main.c @@ -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 // fprintf(), NULL +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/unit-tests/test-cases/image-suffix/main.c b/unit-tests/test-cases/image-suffix/main.c index 28b4c8e..204744e 100644 --- a/unit-tests/test-cases/image-suffix/main.c +++ b/unit-tests/test-cases/image-suffix/main.c @@ -22,6 +22,7 @@ */ #include #include +#include #include "test.h" diff --git a/unit-tests/test-cases/initializer-bounds-check/Makefile b/unit-tests/test-cases/initializer-bounds-check/Makefile index aa35765..42f9e42 100644 --- a/unit-tests/test-cases/initializer-bounds-check/Makefile +++ b/unit-tests/test-cases/initializer-bounds-check/Makefile @@ -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 diff --git a/unit-tests/test-cases/initializer-bounds-check/main.c b/unit-tests/test-cases/initializer-bounds-check/main.c index f466342..bd4a512 100644 --- a/unit-tests/test-cases/initializer-bounds-check/main.c +++ b/unit-tests/test-cases/initializer-bounds-check/main.c @@ -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; } diff --git a/unit-tests/test-cases/insert-libraries-with-suid/Makefile b/unit-tests/test-cases/insert-libraries-with-suid/Makefile index b270917..c06cad5 100644 --- a/unit-tests/test-cases/insert-libraries-with-suid/Makefile +++ b/unit-tests/test-cases/insert-libraries-with-suid/Makefile @@ -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 diff --git a/unit-tests/test-cases/interpose-shared-cache/main.c b/unit-tests/test-cases/interpose-shared-cache/main.c index 192b3b6..93ef898 100644 --- a/unit-tests/test-cases/interpose-shared-cache/main.c +++ b/unit-tests/test-cases/interpose-shared-cache/main.c @@ -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@ * @@ -24,15 +24,20 @@ #include // exit(), EXIT_SUCCESS #include #include +#include #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"); diff --git a/unit-tests/test-cases/interpose-shared-cache/mymalloc.c b/unit-tests/test-cases/interpose-shared-cache/mymalloc.c index 9afe7f1..bca0938 100644 --- a/unit-tests/test-cases/interpose-shared-cache/mymalloc.c +++ b/unit-tests/test-cases/interpose-shared-cache/mymalloc.c @@ -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@ * @@ -22,15 +22,34 @@ */ #include +#include #include +#include #include +#include -// 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 index 0000000..7fab8fc --- /dev/null +++ b/unit-tests/test-cases/loader_path-symlink/Makefile @@ -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) + +# +# 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 index 0000000..b72a1a5 --- /dev/null +++ b/unit-tests/test-cases/loader_path-symlink/bar.c @@ -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 index 0000000..3695dc9 --- /dev/null +++ b/unit-tests/test-cases/loader_path-symlink/foo.c @@ -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 index 0000000..4c91a7c --- /dev/null +++ b/unit-tests/test-cases/loader_path-symlink/main.c @@ -0,0 +1,14 @@ +#include +#include +#include + +#include "test.h" + +extern void foo(); + +int main() +{ + foo(); + PASS("loader_path-symlink"); + return EXIT_SUCCESS; +} diff --git a/unit-tests/test-cases/pie-text-reloc/Makefile b/unit-tests/test-cases/pie-text-reloc/Makefile index a83adcd..31d75d6 100644 --- a/unit-tests/test-cases/pie-text-reloc/Makefile +++ b/unit-tests/test-cases/pie-text-reloc/Makefile @@ -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 index 0000000..9465192 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/Makefile @@ -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 index 0000000..18d7633 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/bar.c @@ -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 index 0000000..cb30818 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/baz.c @@ -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 index 0000000..5fbf7f4 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/baz.exp @@ -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 index 0000000..72b3c29 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/foo.c @@ -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 index 0000000..aff96a1 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/foo.exp @@ -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 index 0000000..3df9d3d --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/frob.c @@ -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 index 0000000..f12dd10 --- /dev/null +++ b/unit-tests/test-cases/re-export-symbol-dylib/main.c @@ -0,0 +1,44 @@ + +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#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; +} + diff --git a/unit-tests/test-cases/re-export-symbol/Makefile b/unit-tests/test-cases/re-export-symbol/Makefile index 3be2415..c02f912 100644 --- a/unit-tests/test-cases/re-export-symbol/Makefile +++ b/unit-tests/test-cases/re-export-symbol/Makefile @@ -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 diff --git a/unit-tests/test-cases/read-only-stubs/main.c b/unit-tests/test-cases/read-only-stubs/main.c index fdadfc7..b9420c7 100644 --- a/unit-tests/test-cases/read-only-stubs/main.c +++ b/unit-tests/test-cases/read-only-stubs/main.c @@ -23,11 +23,13 @@ #include // fprintf(), NULL #include // exit(), EXIT_SUCCESS #include +#include #include #include #include #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 diff --git a/unit-tests/test-cases/restrict-environ/Makefile b/unit-tests/test-cases/restrict-environ/Makefile index 8aa6bea..a22a543 100644 --- a/unit-tests/test-cases/restrict-environ/Makefile +++ b/unit-tests/test-cases/restrict-environ/Makefile @@ -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 diff --git a/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c b/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c index d4f0b33..9857c71 100644 --- a/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c +++ b/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #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 index 0000000..ec5d680 --- /dev/null +++ b/unit-tests/test-cases/rpath-introspection/Makefile @@ -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 index 0000000..3695dc9 --- /dev/null +++ b/unit-tests/test-cases/rpath-introspection/foo.c @@ -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 index 0000000..6eba6da --- /dev/null +++ b/unit-tests/test-cases/rpath-introspection/main.c @@ -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 +#include +#include +#include +#include + +#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; +} diff --git a/unit-tests/test-cases/rpath-loader_path-dlopen/main.c b/unit-tests/test-cases/rpath-loader_path-dlopen/main.c index 2b1cc25..69b4a59 100644 --- a/unit-tests/test-cases/rpath-loader_path-dlopen/main.c +++ b/unit-tests/test-cases/rpath-loader_path-dlopen/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "test.h" diff --git a/unit-tests/test-cases/suid-environ/Makefile b/unit-tests/test-cases/suid-environ/Makefile index 7797d2e..6356a4a 100644 --- a/unit-tests/test-cases/suid-environ/Makefile +++ b/unit-tests/test-cases/suid-environ/Makefile @@ -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 diff --git a/unit-tests/test-cases/symbol-resolver-basic/Makefile b/unit-tests/test-cases/symbol-resolver-basic/Makefile index cfc8ac0..f38f287 100644 --- a/unit-tests/test-cases/symbol-resolver-basic/Makefile +++ b/unit-tests/test-cases/symbol-resolver-basic/Makefile @@ -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 index 0000000..2d0c380 --- /dev/null +++ b/unit-tests/test-cases/symbol-resolver-interposed/Makefile @@ -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/launch-cache/dsc_slider.h b/unit-tests/test-cases/symbol-resolver-interposed/foo.c similarity index 57% rename from launch-cache/dsc_slider.h rename to unit-tests/test-cases/symbol-resolver-interposed/foo.c index 4979562..8e9ff7e 100644 --- a/launch-cache/dsc_slider.h +++ b/unit-tests/test-cases/symbol-resolver-interposed/foo.c @@ -1,6 +1,5 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2010 Apple Inc. All rights reserved. +/* + * Copyright (c) 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,22 +21,33 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include -#ifdef __cplusplus -extern "C" { -#endif +static int which_foo = 0; -// -// 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, ...) ); +void set_foo(int x) +{ + which_foo = x; +} +static int foo_ten() +{ + return 10; +} -#ifdef __cplusplus +static int foo_zero() +{ + return 0; } -#endif + + +// 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 index 0000000..2c1d57b --- /dev/null +++ b/unit-tests/test-cases/symbol-resolver-interposed/foo.h @@ -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 index 0000000..32c1ccb --- /dev/null +++ b/unit-tests/test-cases/symbol-resolver-interposed/main.c @@ -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 // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include + +#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 index 0000000..a85ee6a --- /dev/null +++ b/unit-tests/test-cases/symbol-resolver-interposed/myfoo.c @@ -0,0 +1,10 @@ + +#include +#include "foo.h" + +int myfoo() +{ + return 20; +} + +DYLD_INTERPOSE(myfoo, foo) diff --git a/unit-tests/test-cases/symbol-resolver-pointer/Makefile b/unit-tests/test-cases/symbol-resolver-pointer/Makefile index 9143671..bf8e689 100644 --- a/unit-tests/test-cases/symbol-resolver-pointer/Makefile +++ b/unit-tests/test-cases/symbol-resolver-pointer/Makefile @@ -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 index 0000000..71d7002 --- /dev/null +++ b/unit-tests/test-cases/terminator-bounds-check/Makefile @@ -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/dyld-slide/main.c b/unit-tests/test-cases/terminator-bounds-check/main.c similarity index 66% rename from unit-tests/test-cases/dyld-slide/main.c rename to unit-tests/test-cases/terminator-bounds-check/main.c index a689f63..50177bb 100644 --- a/unit-tests/test-cases/dyld-slide/main.c +++ b/unit-tests/test-cases/terminator-bounds-check/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,30 +20,28 @@ * * @APPLE_LICENSE_HEADER_END@ */ -#include // EXIT_SUCCESS -#include -#include +#include // fprintf(), NULL +#include // exit(), EXIT_SUCCESS -#include "test.h" +#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); +} -// -// 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"); - + // stomp on terminator routine to point into libSystem (_rand) + terminators[0] = &rand; return EXIT_SUCCESS; } - - diff --git a/unit-tests/test-cases/text-relocs-perms/foo.c b/unit-tests/test-cases/text-relocs-perms/foo.c index 6a03b28..b644c3d 100644 --- a/unit-tests/test-cases/text-relocs-perms/foo.c +++ b/unit-tests/test-cases/text-relocs-perms/foo.c @@ -23,6 +23,7 @@ #include // fprintf(), NULL #include // exit(), EXIT_SUCCESS #include +#include #include #include #include @@ -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 diff --git a/unit-tests/test-cases/text-relocs-perms/main.c b/unit-tests/test-cases/text-relocs-perms/main.c index b4994b0..fc07f17 100644 --- a/unit-tests/test-cases/text-relocs-perms/main.c +++ b/unit-tests/test-cases/text-relocs-perms/main.c @@ -23,12 +23,15 @@ #include // fprintf(), NULL #include // exit(), EXIT_SUCCESS #include +#include #include #include #include #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 diff --git a/unit-tests/test-cases/text-relocs/Makefile b/unit-tests/test-cases/text-relocs/Makefile index a024a28..1048e84 100644 --- a/unit-tests/test-cases/text-relocs/Makefile +++ b/unit-tests/test-cases/text-relocs/Makefile @@ -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: diff --git a/unit-tests/test-cases/text-relocs/space.s b/unit-tests/test-cases/text-relocs/space.s index 2767b5d..0593e1e 100644 --- a/unit-tests/test-cases/text-relocs/space.s +++ b/unit-tests/test-cases/text-relocs/space.s @@ -1,2 +1,3 @@ .text + .align 2 _junk: .space 1024*1024 diff --git a/unit-tests/test-cases/tlv-initializer/Makefile b/unit-tests/test-cases/tlv-initializer/Makefile index 62cd36a..6a6d74c 100644 --- a/unit-tests/test-cases/tlv-initializer/Makefile +++ b/unit-tests/test-cases/tlv-initializer/Makefile @@ -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/tlv-initializer/get.s b/unit-tests/test-cases/tlv-initializer/get.s index 5116395..919667a 100644 --- a/unit-tests/test-cases/tlv-initializer/get.s +++ b/unit-tests/test-cases/tlv-initializer/get.s @@ -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 diff --git a/unit-tests/test-cases/tlv-initializer/main.c b/unit-tests/test-cases/tlv-initializer/main.c index af11a86..3f89123 100644 --- a/unit-tests/test-cases/tlv-initializer/main.c +++ b/unit-tests/test-cases/tlv-initializer/main.c @@ -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@ * @@ -26,24 +26,24 @@ #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); } diff --git a/unit-tests/test-cases/tlv-terminators/Makefile b/unit-tests/test-cases/tlv-terminators/Makefile index f27c54e..9094732 100644 --- a/unit-tests/test-cases/tlv-terminators/Makefile +++ b/unit-tests/test-cases/tlv-terminators/Makefile @@ -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 index 0000000..a0a54a1 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/Makefile @@ -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 index 0000000..9a146f4 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/b.c @@ -0,0 +1,10 @@ +#include +#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 index 0000000..0d79e7c --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/c.c @@ -0,0 +1,8 @@ +#include + + + +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 index 0000000..c703835 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/common.c @@ -0,0 +1,29 @@ +#include "common.h" +#include + +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 index 0000000..0094023 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/common.h @@ -0,0 +1,7 @@ +#include + +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 index 0000000..e7edc55 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/main.c @@ -0,0 +1,19 @@ +#include // fprintf(), NULL +#include // 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 index 0000000..81c4043 --- /dev/null +++ b/unit-tests/test-cases/upward-dylib-init-order/u.c @@ -0,0 +1,10 @@ +#include +#include "common.h" + + +static __attribute__((constructor)) void myInit() +{ + setU(); + //fprintf(stderr, "init u\n"); +} + diff --git a/unit-tests/test-cases/upward-dylib/Makefile b/unit-tests/test-cases/upward-dylib/Makefile index 9488bac..b33a842 100644 --- a/unit-tests/test-cases/upward-dylib/Makefile +++ b/unit-tests/test-cases/upward-dylib/Makefile @@ -23,11 +23,11 @@ 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: diff --git a/unit-tests/test-cases/upward-dylib/down.c b/unit-tests/test-cases/upward-dylib/down.c index c5624bd..f576ad6 100644 --- a/unit-tests/test-cases/upward-dylib/down.c +++ b/unit-tests/test-cases/upward-dylib/down.c @@ -16,7 +16,7 @@ int getdown() return state; } -void other() +int getdownsup() { - whatsup(); + return whatsup(); } \ No newline at end of file diff --git a/unit-tests/test-cases/upward-dylib/down.h b/unit-tests/test-cases/upward-dylib/down.h index 534eb92..e4eb56c 100644 --- a/unit-tests/test-cases/upward-dylib/down.h +++ b/unit-tests/test-cases/upward-dylib/down.h @@ -1,2 +1,3 @@ extern int getdown(); +extern int getdownsup(); diff --git a/unit-tests/test-cases/upward-dylib/main.c b/unit-tests/test-cases/upward-dylib/main.c index 06b272b..302478a 100644 --- a/unit-tests/test-cases/upward-dylib/main.c +++ b/unit-tests/test-cases/upward-dylib/main.c @@ -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 index 0000000..25ee4eb --- /dev/null +++ b/unit-tests/test-cases/upward-dylib/main2.c @@ -0,0 +1,20 @@ +#include // fprintf(), NULL +#include // 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; +} + + -- 2.45.2