--- /dev/null
+
+dyld-208
+<rdar://problem/10879179> Correct @path to still work with symlinks
+
+dyld-207
+<rdar://problem/10825175> dyld should give a better error message if you try to use a newer binary on older OS
+<rdar://problem/10753356> backtraces of LC_MAIN binaries end in tlv_get_addr+136, instead libdyld should export "_start" symbol
+<rdar://problem/10733082> Fix up @rpath based paths during introspection
+<rdar://problem/10657737> Interposition tuples are not respected when binding with resolvers
+
+dyld-206
+<rdar://problem/10442813> Give some warning that DYLD_ env vars are disabled
+
+dyld-205
+<rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
+
+dyld-204.1
+<rdar://problem/10643239> fix initializer ordering of upwardly linked dylibs
+
+dyld-204
+<rdar://problem/10613880> dyld misreads very large addends
+<rdar://problem/10568559> Perform method list sort even if __DATA,__objc_opt_rw is absent
+<rdar://problem/10568179> Remove category attaching from dyld shared cache
+<rdar://problem/10582497> Shared cache method list sorting breaks protocol extended type encodings
+
+dyld-203.1
+<rdar://problem/10491874> initializer not run in only upwardly linked dylib
+
+dyld-203
+<rdar://problem/10419267> update_dyld_shared_cache does not build with libc++
+<rdar://problem/10435247> dyld does not build with libc++
+<rdar://problem/10409027> Add functions to get min OS and sdk versions program was linked with
+<rdar://problem/10399676> DYLD_FRAMEWORK_PATH not mentioned in dlopen() man page
+<rdar://problem/10371927> dsc_extractor not updating LC_FUNCTION_STARTS
+
+dyld-202
+<rdar://problem/8818423> Get rid of crt1.o and jump straight into main() from dyld
+<rdar://problem/10332417> image denied loading by gc_enforcer is left in dyld_all_images_info array
+
+dyld-201
+<rdar://problem/8867781> Use spin lock to guard sAllImageInfos
+
+dyld-200.3
+<rdar://problem/9855733> genCaches fails: "header size miscalculation 0x00006000"
+
+dyld-200.2
+<rdar://problem/9784634> dsc_iterator.cpp needs cases for v7 variants
+
+dyld-200
+<rdar://problem/8942979> update_dyld_shared_cache should accept an 'overlay' along with a 'root' directory option
+Remove PowerPC support
+
+--------------
+dyld-199.5 (iOS 5)
+<rdar://problem/9955829> Update initial image list size
+
+dyld-199.4
+<rdar://problem/9855733> genCaches fails: header size miscalculation
+
+dyld-199.3
+<rdar://problem/7338034> Repair ivar offsets in dyld shared cache
+
+dyld-199.2
+<rdar://problem/8981046> improve Xcode upload of iOS dylibs
+
+dyld-199.1
+<rdar://problem/9510382> correctly adjust ARM movw when in dyld shared cache
+
+dyld-199
+<rdar://problem/9439764> update_dyld_shared_cache requires weak-linked frameworks to be present at shared cache generation time
+<rdar://problem/9447838> Remove armv7 variants from dyld
+
+dyld-198.1
+<rdar://problem/8312145> back out previous change DYLD_XXX restrict check
+
+dyld-198
+<rdar://problem/9035759> corrupt load commands can pass sniff test if 32-bit wraps around
+<rdar://problem/8312145> dyld should restrict DYLD_XXX debugging facilities
+<rdar://problem/7942521> dyld should not allow loading of dylibs without valid signatures
+enable DYLD_PRINT_REBASINGS
+
+dyld-197
+<rdar://problem/7945496> dyld should range check the fixup location of all bindings
+<rdar://problem/8963406> range check initializers and terminators to be within image
+
+dyld-196.2
+<rdar://problem/8987681> dyld should support new armv7 variants
+
+dyld-196.1
+<rdar://problem/9107912> support re-exported symbols from re-exported libraries
+
+dyld-196
+<rdar://problem/9078764> movw/movt don't work in dyld shared cache
+
+
+---------------------
+dyld-195.3 (Mac OS X 10.7.0)
+<rdar://problem/9279770> update_dyld_shared_cache missed libstdc++?
+<rdar://problem/9361288> i386 dyld shared cache overflows after adding libclh.dylib
+
+dyld-195.2
+<rdar://problem/9161945> spurious warning about embedded framework not being put in dyld shared cache
+
+dyld-195
+<rdar://problem/8360915> C++ 0x thread_local destructor support
+<rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
+<rdar://problem/8971061> more verbose messages when vm_protect() fails
+
+dyld-194.1
+Fix uses of libc++abi-static.a
+
+dyld-194
+<rdar://problem/8919005> make interposing available to open source
+<rdar://problem/8874282> __thread implementation doesn't preserve enough registers (ABI issue)
+<rdar://problem/8873628> clang built update_dyld_shared_cache fails at runtime
+
+dyld-193
+<rdar://problem/8735709> dyld should honor CS_RESTRICT in _main like hasRestrictedSegment
+<rdar://problem/8164591> update_dyld_shared_cache -overlay optimizations
+
+dyld-192.1
+<rdar://problem/8812589> dyld has NULL paths in image info array
+
+dyld-192
+<rdar://problem/8750829> dyld's map+slide should be an all or nothing operation
+
+dyld-191.3
+<rdar://problem/8890875> overriding shared cache dylibs with resolvers fails
+
+dyld-191.2
+<rdar://problem/8844174> dyld_stub_binder called repeatedly for $VARIANT$ functions
+<rdar://problem/8845480> update_dyld_shared_cache crash when fat dylib truncated
+
+dyld-191.1
+<rdar://problem/8770940> update_dyld_shared_cache is failing
+
+dyld-191
+<rdar://problem/8736495> ASLR/PIE: dyld's "random padding" algorithm is deterministic
+<rdar://problem/8663923> race condition with flat-namespace lazy binding
+<rdar://problem/8755380> libdyld fails to build with clang-127
+
+dyld-190.1
+remove libdyld.a target
+
+dyld-190
+<rdar://problem/8706192> _NSGetExecutablePath documentation is ambiguous about bufsize
+<rdar://problem/8686676> 11A315: LC_DYLD_ENVIRONMENT does not expand @executable_path
+<rdar://problem/8718137> dyld should avoid arc4random for dylib randomization
+<rdar://problem/8691207> tune trie traversal code for 10.7 compiler
+<rdar://problem/8576479> breaking libSystem into dylibs slows down dyld binding, shared cache should compensate
+<rdar://problem/8686427> update_dyld_shared_cache should not be built no-pie
+
+dyld-189
+<rdar://problem/8274426> dyld(1) man page feedback
+<rdar://problem/8564762> LC_DYLD_ENVIRONMENT should still be honored with __RESTRICT,__restrict section present
+<rdar://problem/8630416> 11A307: DYLD_SHARED_REGION=private crashes
+<rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
+
+dyld-188
+<rdar://problem/4472406> Dynamic linking memory usage seems unusually high for trivial programs
+
+dyld-187
+<rdar://problem/8597637> madvise MADV_FREE calls for LINKEDIT are failing in dyld during launch in iOS
+<rdar://problem/8602453> dyld allImageInfos messed up with duplicate IOKit
+
+dyld-186
+<rdar://problem/8109857> dyld: Pick up changes from libsystem_kernel reorganisation in dyld's build.
+<rdar://problem/5847052> Shared Region Base Should Slide at Boot Time
+<rdar://problem/6650578> Multiple /dev/urandom accesses on every process exec
+
+dyld-185
+<rdar://problem/8345025> text relocs don't work if only S_ATTR_EXT_RELOC is used
+<rdar://problem/8400815> DYLD_FORCE_FLAT_NAMESPACE=YES causes process to spin in DYLD-STUB$$bzero
+
+dyld-184
+<rdar://problem/8554137> Add cache slide value to dyld_all_image_infos
+
+dyld-183.1
+<rdar://problem/8521882> dyld proper does not need dyld_stub_binder.o
+
+dyld-183
+<rdar://problem/8274192> dyld needs to call new kernel interface to register metadata
+<rdar://problem/8448281> ASLR side build causes 15-30% regression in most launch times
+<rdar://problem/8440902> Support version-checked framework/library override paths
+<rdar://problem/8440934> Support LC_DYLD_ENVIRONMENT load command
+<rdar://problem/8454987> function starts info should be copied into dyld shared cache
+
+dyld-182
+<rdar://problem/8432001> Merge Jasper dyld changes to trunk
+
+dyld-181.1
+<rdar://problem/8455429> 11A270: FNPLicensingService crashes
+
+dyld-181
+<rdar://problem/8403002> 11A238a: AutoDesk AutoCAD beta 4 crashes on launch (dyld)
+<rdar://problem/8345799> update_dyld_shared_cache-173 project fails to build with LLVM compiler 2.0.
+
+dyld-180
+<rdar://problem/8352892> 8F63: dyld-179.4 fails on missing /usr/local/lib/system/libc.a
+<rdar://problem/8344449> 11A238a: AutoDesk AutoCAD beta 4 crashes on launch
+<rdar://problem/8313034> 11A244: overlapping files in libdyld & update_dyld_shared_cache
+
+
+dyld-179.7 (iOS 4.2)
+<rdar://problem/8543820> range check initializers
+
+dyld-179.6
+<rdar://problem/8515776> dyld_shared_cache_extract_dylibs shouldn't return '-1' when arch already exists
+
+dyld-179.5
+<rdar://problem/8425790> Need a version of dyld_shared_cache_extract_dylbs that lipo's results
+<rdar://problem/8365622> Need a version of dyld_shared_cache_extract_dylbs that reports progress
+<rdar://problem/8320866> back out work around for 8151909
+
+dyld-179.4
+<rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
+
+dyld-179.3.1
+<rdar://problem/8327834> 11A245: Photoshop CS4 fails in SmokeTest because of crash in FNPLicensingService (dyld)
+
+dyld-179.3
+<rdar://problem/8305049> 11A238a: All Adobe CS4 applications crash on launch
+
+dyld-179.2
+<rdar://problem/8290793> 11A239: leaks throws an exception, doesn't work
+
+dyld-179.1
+<rdar://problem/8284123> libdsc.a in Jasper SDK needs to be arm version (is x86 version)
+
+dyld-179
+<rdar://problem/8284944> update_dyld_shared_cache does not work with individual symbol re-exports
+
+dyld-178
+<rdar://problem/8284044> Support __thread variables exported from dylibs
+<rdar://problem/7356532> update dyld_all_image_infos more often, for better crash logs
+
+dyld-177
+<rdar://problem/8214567> We need an extractor able to pull the shared symbols cache apart
+<rdar://problem/8263666> Don't put slide info in dyld shared cache in Jasper
+<rdar://problem/8268602> dyld does not prevent loading of unsigned dylib
+
+dyld-176
+<rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
+
+dyld-175
+<rdar://problem/8235734> ObjC optimized shared cache does not slide
+
+dyld-174
+<rdar://problem/8198287> Need to merge Apex ObjC method list optimizations in dyld shared cache to TOT dyld
+<rdar://problem/8115131> implement ASLR for dyld shared cache for iOS
+
+dyld-173
+<rdar://problem/8144421> fix permissions on rebased binary not slid
+
+dyld-172.2
+<rdar://problem/8191063> dyld should not include SystemIntegrity headers on embedded platform
+Have DYLD_PRINT_BINDINGS print out when resolver functions are called
+
+dyld-172.1
+<rdar://problem/8166086> fix visibility of dyld_func_lookup depending if libdyld is .a or .dylib
+
+dyld-172
+Add hack to work around 8151909
+Alter project to build for both kinds of libSystems
+
+dyld-171
+Add support for individual symbol re-exports
+Add support for building for iOS
+
+dyld-170
+<rdar://problem/7508424> ER: more metadata for dyld errors
+
+dyld-169
+<rdar://problem/7995213> update_dyld_shared_cache needs to support resolver functions
+Implement some cxa stuff to work with next c++abi.a
+
+dyld-168
+<rdar://problem/7901042> dyld should move shared cache file into /var/run instead of open-unlinking
+<rdar://problem/7940222> private shared cache calls mmap twice for each range
+<rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
+<rdar://problem/7935000> 11A168: update_dyld_shared_cache problems during install
+<rdar://problem/7918210> use of C++ thread local initializer causes infinite recursion
+<rdar://problem/7932725> (from iPhoneOS) dyld should stub out mach_error_string for 8KB RAM savings per process
+<rdar://problem/7937695> (from iPhoneOS) verify that replacement is in this image
+
+dyld-167.2
+<rdar://problem/7956031> dyld: Use libsystem_mach.a from /usr/local/lib/dyld to build dyld
+
+dyld-167.1
+<rdar://problem/7901042> dyld should move shared cache file into /tmp instead of open-unlinking
+
+dyld-167
+<rdar://problem/7859049> dyld support for function specialization
+<rdar://problem/7740779> dyld should directly call __cxa_finalize(), part 2
+<rdar://problem/7796738> dyld support for thread local variables
+
+
+dyld-166
+<rdar://problem/7739489> ER: facility to detect which images were loaded at runtime
+<rdar://problem/7818451> update_dyld_shared_cache -verify fails
+
+
+dyld-165
+<rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
+<rdar://problem/7744084> Sort method lists in dyld shared cache
+
+
+dyld-164
+<rdar://problem/7733433> Move libdyldapis over to a dylib target for Libsystem
+<rdar://problem/7675254> pruneEnvironmentVariables does not update gLinkContext.apple
+
+
+dyld-163
+<rdar://problem/7740033> Warning message is misleading
+<rdar://problem/7740658> update_dyld_shared_cache should not run past end of splitseginfo if zero terminator is missing
+<rdar://problem/6666832> dyld should directly call __cxa_finalize(), part 1
+
+
+dyld-162
+<rdar://problem/7662176> crash in update_dyld_shared_cache when checking if current cache is out of date
+<rdar://problem/7444994> ER: Support upward dylib dependencies
+
+
+dyld-161
+<rdar://problem/7628929> __builtin_return_address broke for PPC
+<rdar://problem/7658265> SWBDC error: 'ld: duplicate symbol' while building 'dyld-160~48' in '11A108a-llvmgcc-2324.3'
+
+
+dyld-160
+<rdar://problem/7234280> Environment variable to cause dyld to dump rpaths used during loading
+<rdar://problem/7595563> update_dyld_shared_cache failed: internal error, new trie allocated to far from fLinkeditBase
+<rdar://problem/7589167> dyld still slides executables when PIE is disabled by the kernel
+
+
+dyld-159
+<rdar://problem/7343139> update_dyld_shared_cache fails to find roots when targetting NFS
+<rdar://problem/7484408> dyld does not call initializers from all S_MOD_INIT_FUNC_POINTERS sections
+<rdar://problem/7544082> move _dyld_func_lookup prototype to dyld_priv.h
+
+
+dyld-158
+<rdar://problem/7486405> dyld attempts to load libraries via rpath when already loaded
+<rdar://problem/5274722> dyld shared cache can be more random
+
+
+dyld-157
+<rdar://problem/7481480> switch to use libc++abi-static.a instead of libstdc++-static.a
+
+
+dyld-156
+<rdar://problem/7408768> remove DYLD_NO_PIE from man page
+<rdar://problem/7445102> support multiple dylibs with non-intersected weak symbols in shared cache
+<rdar://problem/7466900> dyld sends bogus library unload notice to CoreSymbolication during dlopen_preflight()
+<rdar://problem/7455017> spelling: "was build against" -> "was built against"
+
+
+dyld-155
+<rdar://problem/7451030> sjlj based exception support needs to be conditionalized for arm - not iPhoneOS
+
+
+dyld-154
+<rdar://problem/7272661> Need to enable CoreSymbolication load/unload notices on iPhoneOS
+
+
+dyld-153
+<rdar://problem/7327864> add field to dyld_all_image_infos pointing to dyld_all_image_infos
+
+
+dyld-152
+<rdar://problem/7302432> Minimize system calls and mach messages during dyld startup
+<rdar://problem/7302383> Why is checkSharedRegionDisable() !__LP64__
+
+
+dyld-151
+<rdar://problem/7223037> dyld support for sliding PIE binaries in the kernel
+<rdar://problem/7165731> libdyld does not install multiple headers at installhdrs time
+<rdar://problem/6937560> dlopen() crash when executable contains LC_RPATH and executable file is deleted while running
+<rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
+
+
+----------------------------------
+
+dyld-150 ( iPhoneOS 3.1 )
+<rdar://problem/7043575> flat_namespace linkage error in update_dyld_shared_cache should be a warning not an error
+<rdar://problem/7084861> Have dyld save load addr + UUID for executable images
+<rdar://problem/7101832> Libsystem fails to link with latest gcc: dyld missing _dyld_func_lookup
+
+
+dyld-149
+<rdar://problem/7017050> dlopen() not working with non-canonical paths
+<rdar://problem/7033445> update_dyld_shared_cache fails creating shared cache
+
+
+dyld-148
+<rdar://problem/7022281> shared cache file offsets are inconsistent
+
+
+dyld-147
+<rdar://problem/6995143> move install location for update_dyld_shared_cache and man page to local
+<rdar://problem/7014995> imageFileModDate in dyld_all_image_infos is sometimes bogus for the first image therein
+<rdar://problem/7014397> dyld_shared_cache_util should optionally print VM load addresses for each dylib
+<rdar://problem/7014783> uuid_t not defined in dyld_priv.h
+
+
+dyld-146
+<rdar://problem/7008875> Save load information (load addr + UUID) to dyld_all_image_infos for images from outside the shared cache
+<rdar://problem/7007923> update_dyld_shared_cache should improve warning above deployment target
+
+
+dyld-145
+<rdar://problem/7000405> optimize stubs in dyld shared cache to be no-PIC
+<rdar://problem/6995143> dyld_shared_cache_util built by dyld target should go in platform directory
+<rdar://problem/7001159> dyld_shared_cache_util should list LC_REEXPORT_DYLIB libraries as dependents
+
+
+dyld-144
+<rdar://problem/6995143> dyld_shared_cache_util built by dyld target should go in platform directory
+<rdar://problem/6775261> API: Detect shared cache overrides
+
+
+dyld-143
+<rdar://problem/6956867> ER: Tool to list the contents of a dyld shared cache image
+<rdar://problem/6959334> ARM support for dsc_iterator
+
+
+dyld-142
+<rdar://problem/6965455> text relocs fail in large segments
+<rdar://problem/6945944> Variable whose data is overwritten needs to be marked `volatile'
+<rdar://problem/6921370> dyld option to print time for each initializer, Apple's or the app's
+
+
+dyld-141
+<rdar://problem/6927281> update_dyld_shared_cache assumes -root path contains no symlinks
+sync with SnowLeopard dyld-132.13
+
+
+dyld-140
+<rdar://problem/6153040> load code signature from file, and before mapping the file
+
+
+dyld-139.1
+<rdar://problem/6868811> Northstar7C62: dyld-139 fails to build
+
+
+dyld-139
+<rdar://problem/6780449> dyld on iPhoneOS uses libgcc_eh.a which uses pthread_key_create which does not work
+<rdar://problem/6780192> dyld can leak when an internal exception in thrown
+<rdar://problem/6331300> support compressed LINKEDIT on iPhone
+sync with SnowLeopard dyld-132.11
+
+
+dyld-138.1
+<rdar://problem/6790993> New mechanism to instruct dyld whether to check for libs outside the shared cache
+
+
+dyld-138
+<rdar://problem/6814596> need to handle symlinks when dylib is in cache but file is intentionally missing
+<rdar://problem/6825135> dyld should avoid stat()ing libraries present in the shared cache unless magic override file is present
+
+
+dyld-137
+<rdar://problem/6792383> dyld reports image not found if it is in the shared cache but no binary is present on disk
+sync with SnowLeopard dyld-132.10
+
+
+dyld-136
+<rdar://problem/6776343> dyld reports bogus fat offset when registering shared cache signature
+
+
+dyld-135
+<rdar://problem/6268421> iPhone: Need objc optimizations in iPhone OS shared cache
+
+
+dyld-134
+<rdar://problem/4759373> build armv6 dyld with Thumb
+sync with SnowLeopard
+
+
+
+dyld-133.1
+fix for all arm architectures
+
+
+dyld-133
+<rdar://problem/6268380> make dyld that uses shared cache on iPhone OS
+
+
+----------------------------------
+
+dyld-132.13 ( Mac OS X 10.6 )
+<rdar://problem/6898370> classic images not unmapped when unloaded
+
+
+dyld-132.12
+<rdar://problem/6882159> dyld's dtrace notification should be done after rebasing
+
+
+dyld-132.11
+<rdar://problem/6803496> Remove dyld workaround for McAfee VirusScan
+<rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
+
+
+dyld-132.10
+<rdar://problem/6785160> dyld's abort_report_np() doesn't abort
+<rdar://problem/6794063> 10A331: CUPS crashes when calling sandbox_init
+
+
+dyld-132.9
+<rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
+<rdar://problem/6739742> Exception Backtrace being obscured by _mh_execute_header
+<rdar://problem/6766057> Silverlight Preferences.app crashes
+
+
+dyld-132.8
+<rdar://problem/6735870> dlopen() leaks send right obtained from mach_thread_self()
+<rdar://problem/6732715> dyld's calloc() allocates too few bytes
+<rdar://problem/6678640> dyld lazy binding is not thread safe
+
+
+dyld-132.7
+<rdar://problem/6651342> need a way other than setgid to have dyld launch a process securely, ignoring DYLD_ env vars etc
+<rdar://problem/6721803> Need mapping of files to their offsets into the dyld_shared_cache files on disk
+
+
+dyld-132.6
+<rdar://problem/6618466> update_dyld_shared_cache -overlay should check root dyld caches
+<rdar://problem/6619554> NSCreateObjectFileImageFromMemory() call vm_deallocate even if application used malloc()
+
+
+dyld-132.5
+<rdar://problem/6655235> dyld is missing some binding optimizations
+<rdar://problem/6647316> symbol lookups in the new trie structure should be faster
+<rdar://problem/6570879> weak binding done too early with inserted libraries
+
+
+dyld-132.4
+<rdar://problem/6629428> improve statistics output
+<rdar://problem/6628413> better error message if LC_RPATH is used in dylib destined for shared cache
+<rdar://problem/6622898> dladdr() broke when image has debug symbols
+<rdar://problem/6555720> 10A264: Google Earth 5.0 crashes on quit
+<rdar://problem/6591933> man page should better explain update_dyld_shared_cache -root option
+
+
+dyld-132.3
+<rdar://problem/6527653> remove setjmp/longjmp from _simple_printf in dyld
+<rdar://problem/6580333> Typo in dyld(3) man page
+<rdar://problem/6510301> race condition in pre-10.6 style lazy pointer binding
+<rdar://problem/6573344> make cheaper dladdr() that just returns image path
+<rdar://problem/6563887> 10A266 - Adobe InDesign CS4 crashes on launch
+<rdar://problem/6570113> dyld is not setting imageFileModDate in dyld_image_info
+<rdar://problem/6493245> Logic Pro crashes after creating a new document on SnowLeopard
+
+
+dyld-132.2
+<rdar://problem/6293143> adopt new CoresSymbolication notification mechanism
+<rdar://problem/6536810> Alter libdyld.a to not need libsystem to link with dylib1.o
+<rdar://problem/6530593> 10A256a: update_dyld_shared_cache -verify crashes (probably due to lack of a shared cache)
+
+
+dyld-132.1
+<rdar://problem/6552051> update_dyld_shared_cache failed: no writable segment in Cocoa framework
+
+
+dyld-132
+<rdar://problem/6490500> CrashTracer: [USER] 1 crash in Neverwinter Nights 2
+
+
+dyld-131
+<rdar://problem/6501078> libgmalloc broken on 10A10246 and 10A251 (libgmalloc not inserted early enough)
+
+
+dyld-130
+<rdar://problem/6497528> Rosetta circular dependency spew
+<rdar://problem/6347414> @rpath and @loader_path Should be Documented in man page
+Prune unneeded load commands from shared cache images
+
+
+dyld-129
+<rdar://problem/6479007> dyld-128 no longer builds for armv6
+<rdar://problem/6481443> 10A244: iTunes crashes trying to load MobileDevice.framework
+
+
+dyld-128
+<rdar://problem/6474295> ImageLoader objects can be made smaller
+<rdar://problem/6198151> dyld spin in SecurityAgent
+<rdar://problem/6285470> ImageLoaderMachO::makeImportSegmentWritable() doesn't do it
+
+
+dyld-127
+<rdar://problem/6464419> Add all_image_infos for CrashReporter
+some fixes for compressed LINKEDIT
+
+
+dyld-126
+<rdar://problem/6459812> x86_64 export trie nodes may have large negative address
+<rdar://problem/6442327> update_dyld_shared_cache man page should be updated to reflect new SL behavior
+
+
+dyld-125
+<rdar://problem/6347414> @rpath and @loader_path should be documented in man page
+<rdar://problem/6421511> Add NOP after trap instruction in _dyld_fatal_error
+
+
+dyld-124
+<rdar://problem/6273311> update_dyld_shared_cache should not automatically run by default
+Add support for arm shared caches
+Add support for __program_vars section
+Add more -verify sanity checks
+
+
+dyld-123
+<rdar://problem/6117580> Add -verify option to update_dyld_shared_cache
+<rdar://problem/6408758> [dyld] Errors reported by the upcoming compiler flags verifier
+<rdar://problem/6408518> 10A224: update_dyld_shared_cache warns about a condition in B&I-built frameworks
+<rdar://problem/4697610> stop shadowing old data structures
+<rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
+
+
+dyld-122
+<rdar://problem/6361143> Need a way to determine if a gdb call to dlopen() would block
+<rdar://problem/6328003> Drop Rosetta shared cache generation by default / at install
+<rdar://problem/6400750> "terminaton function" misspelled
+<rdar://problem/6399150> Make it easier to use shared caches from foreign systems
+<rdar://problem/6369189> SnowLeopard10A210: MATLAB 7.6 crashes on launch
+
+
+dyld-121.1
+<rdar://problem/6364434> CrashTracer: crash in iTunes at com.apple.QuickTimeComponents.component
+
+
+dyld-121
+<rdar://problem/6373929> libdyld.a is missing dyld_stub_binder
+
+
+dyld-120
+<rdar://problem/6315338> 10A197 - After Effects 8.0.2 fails to launch after installation
+
+
+dyld-119
+<rdar://problem/6364540> 10A212: update_dyld_shared_cache failed: string buffer exhausted
+<rdar://problem/6357561> Oracle client crashes
+
+
+dyld-118.1
+<rdar://problem/6350500> Cope with duplicate protocol references in shared cache construction
+
+
+dyld-118
+<rdar://problem/6336723> 10A197 vs 10A190: Applications warm launch time slowdown due to dyld
+
+
+dyld-117
+<rdar://problem/6318449> 10A198 - Final Cut Pro 6.0.4 crashes on launch [INTRODUCED BY dyld-115 IN 10A197]
+
+
+dyld-116
+<rdar://problem/6004942> Pandora Desktop (Adobe AIR Framework) crashes on launch [INTRODUCED BY dyld-101 IN 10A14]
+<rdar://problem/6250902> dyld should use libunwind
+<rdar://problem/5408556> Possible leak originating in speech at LoadEngine
+<rdar://problem/6315314> update_dyld_shared_cache manpage typos 'parition', 'assignes', 'choosen'
+
+
+dyld-115
+<rdar://problem/6061574> LINKEDIT content could be greatly compressed
+
+
+dyld-114
+<rdar://problem/6231688> update_dyld_shared_cache needs to provide progress that the Installer can display
+<rdar://problem/6231686> update_dyld_shared_cache needs to be able to look at an Installation sandbox
+<rdar://problem/6293143> dyld isn't calling csdlc_notify on library unload
+<rdar://problem/6277916> warning, could not bind Mail.app because realpath() failed on /AppleInternal/.../XILog.framework
+
+
+dyld-113
+<rdar://problem/6252320> NSAddressOfSymbol(NULL) should return NULL and not crash
+<rdar://problem/6255192> dlopen() should fail to load (non-pie) executables
+
+
+dyld-112
+<rdar://problem/6188100> _replacement misspelled as _replacement in dyld-interposing.h
+<rdar://problem/6176037> make _dyld_find_unwind_sections() faster
+
+
+dyld-111
+<rdar://problem/6161821> improve bad relocation error message
+<rdar://problem/6190458> Need load/unload notification sent to com.apple.vmudl service when requested
+<rdar://problem/6188100> _replacement misspelled as _replacement in dyld-interposing.h
+
+
+dyld-110
+<rdar://problem/5703616> check libSystem is correct in shared cache file before loading it
+<rdar://problem/5557882> function names returned by dladdr do not match reality
+<rdar://problem/5780431> update_dyld_shared_cache .map files should be written atomically
+<rdar://problem/6145451> dlopen(RTLD_NOLOAD) does not need to throw an internal exception
+<rdar://problem/4090265> Explanation for the RTLD_NEXT flag in dlsym(3) needs clarification
+<rdar://problem/5951327> DYLD_FALLBACK_LIBRARY_PATH should not apply to dlopen() of a partial path
+<rdar://problem/6182301> No shared cache present on first boot
+
+
+dyld-109
+<rdar://problem/5925940> Safe Boot should disable dyld shared cache
+<rdar://problem/5706594> CrashTracer: crash in preFetch() reading off end of LINKEDIT
+<rdar://problem/6109435> DYLD_NO_PIE env variable should be documented in dyld manpage
+<rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
+<rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+
+
+dyld-108.1
+<rdar://problem/6156702> armv7/armv5 specific settings needed for dyld
+<rdar://problem/6156653> dyld shouldn't set VALID_ARCHS
+
+
+dyld-108
+<rdar://problem/6120723> ER: dyld based Objective-C selector uniquing
+
+
+dyld-107
+<rdar://problem/5274720> update_dyld_shared_cache should require all source dylibs be owned by root
+<rdar://problem/6073702> Limit what might go in the dyld shared cache
+<rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
+<rdar://problem/5505043> Grow initial dyld pool if needed
+<rdar://problem/5807857> there should be some way to temporarily turn off -pie
+<rdar://problem/6050482> If pie, ignore preferred load address
+<rdar://problem/6053800> Put all_image_infos in its own section to it is easy to find
+
+
+dyld-106
+allow update_dyld_shared_cache to be build 64-bit
+<rdar://problem/5280258> dyld error handling fails in low memory, _simple_salloc() result not checked
+<rdar://problem/4047718> dyld should provide executing program name in incompatible cpu-subtype error message
+
+
+dyld-105
+<rdar://problem/5957134> It should work to set DYLD_FALLBACK_LIBRARY_PATH to empty
+<rdar://problem/5366292> Remove the exceptions made in 4804594 for filemaker
+<rdar://problem/5922117> Remove Tiger-era hacks in dyld for old app compatibility
+<rdar://problem/5901958> Make RTLD_MAIN_ONLY public
+<rdar://problem/5819435> die more gracefully when load commands are malformed
+<rdar://problem/5953438> SWB: dyld build failure when built with -fstack-protector
+<rdar://problem/5950134> dyld man page mis-spelling
+<rdar://problem/5943045> update_dyld_shared_cache does not work when run manually
+
+
+dyld-104
+<rdar://problem/5901583> The optimization to reuse install names as fPath was lost
+<rdar://problem/5888343> Add JIT field to dyld_all_image_infos
+Add _dyld_find_unwind_sections()
+
+
+dyld-103
+<rdar://problem/5805956> NSLinkModule() can crash
+<rdar://problem/5620189> dyld: obsoleted deprecated APIs
+work around for <rdar://problem/5736393>
+add test cases for lazy dylib loading
+
+
+dyld-102
+<rdar://problem/5394977> Man page typo for update_dyld_shared_cache
+<rdar://problem/5490738> Add "malloc is initialized" to the dyld_all_image_infos struct
+<rdar://problem/4045952> better handling of open() errors
+<rdar://problem/5377739> remove <mach-o/dyld_debug.h>
+<rdar://problem/5629960> Use <mach/shared_region.h> instead of <mach/shared_memory_server.h>
+<rdar://problem/5775824> dyld and libdyld should not force building with gcc 4.0
+
+
+dyld-101
+<rdar://problem/5725845> make it easier to find dyld_all_image_infos
+<rdar://problem/5363402> Need _dyld_get_image_slide(const struct mach_header* mh)
+<rdar://problem/5708213> dyld: push code signatures for libs to kernel
+
+
+dyld-100
+<rdar://problem/4737476> dyld falls over when asked to map a split seg library not in the shared region
+<rdar://problem/5595695> dyld: interposing does not work when replacee is thumb
+<rdar://problem/5596017> dyld: all PIE programs crash on launch
+<rdar://problem/5575446> BigBear: not loading libraries at their preferred addresses
+<rdar://problem/5490089> dyld support for arm subtypes
+<rdar://problem/5539483> dyld's prefetching should be turned off for prebound images (and perhaps entirely?)
+<rdar://problem/5602284> dyld-95.3 doesn't build with gcc 4.2
+merge in arm support
+<rdar://problem/5504633> ADOBE: Premiere Pro crashes on quit
+
+----------------------------------
+
+dyld-96.2 (Mac OS X 10.5.2)
+<rdar://problem/5694507> 10.5.2 Regression: 9C18 MeetingMaker crash on launch
+
+dyld-96.1
+<rdar://problem/5537155> update_dyld_shared_cache can crash if dylibs modified out from under it
+<rdar://problem/5562562> crash when dyld interposes on system with partially invalid cache
+<rdar://problem/5563394> com.apple.dyld message spew
+<rdar://problem/5565230> CFSTRs cause crashes in Leopard
+<rdar://problem/5566103> if system shuts down during update_dyld_shared_cache, tmp file is never cleaned up
+<rdar://problem/5623353> dlopen() and dlopen_preflight() can leak on failure
+
+
+
+dyld-95.3 (Mac OS X 10.5)
+<rdar://problem/5503905> Increase initial dyld pool size for 64-bit programs
+
+
+dyld-95.2
+<rdar://problem/5495438> make ppc dyld cache a different file for rosetta
+
+
+dyld-95.1
+<rdar://problem/5388895> McAfee VirusScan fails to launch on Leopard9A513
+
+
+dyld-95
+<rdar://problem/5392427> 9A516 - Keep getting disk full errors
+
+
+dyld-94
+<rdar://problem/5366233> Leopard (9a499): dyld crash with recursive calls to dlclose()
+
+
+dyld-93
+<rdar://problem/4804594> FileMaker Server 8.0v4 helper tools broken by @executable_path security change
+<rdar://problem/5364239> Use msync(MS_SYNC) when building dyld cache
+
+
+dyld-92
+<rdar://problem/5322907> Skype Crashes during launch
+
+
+dyld-91.2
+<rdar://problem/5313172> dlopen() looks too far up stack, can cause crash
+
+
+dyld-91.1
+<rdar://problem/5288790> dyld warning about dtracehelper is too noisy?
+<rdar://problem/5311611> Lots of task_self_trap() system calls in ImageLoader::recursiveInitialization()
+
+
+dyld-91
+<rdar://problem/5249477> use of @loader_path based RPATH can cause dyld to leak
+<rdar://problem/4910107> Dyld_stubs should not be writable on x86
+
+
+dyld-90.2
+<rdar://problem/4860414> generating dyld shared cache generation on first boot makes time to MacBuddy very slow
+
+
+dyld-90.1
+<rdar://problem/5274718> truncated dyld cache file after panic causes hang at boot
+
+
+dyld-90
+<rdar://problem/4892216> stop special casing main executables initializers
+<rdar://problem/4170040> DYLD_INSERT_LIBRARIES doesn't work correctly with initializer functions
+
+
+dyld-89
+<rdar://problem/5097116> dyld could asynchronously request pages it will need
+<rdar://problem/5272001> handle when argv[0] is NULL.
+<rdar://problem/5186317> Foundation built on 9A436 doesn't launch 64 bit apps
+partial fix for: <rdar://problem/4910107> Dyld_stubs should not be writable on x86
+
+
+dyld-88
+<rdar://problem/5233126> update_dyld_shared_cache keeps spewing messages to console
+<rdar://problem/4795421> optimize LINKEDIT region of dyld shared cache
+<rdar://problem/5244184> Support extended __dyld section with NXArgc, etc addresses
+remove call to __xlocale_init()
+Update __OPEN_SOURCE__ conditionals
+
+
+dyld-87
+<rdar://problem/5203587> CFM games use private _dyld_fork_* routines - add back
+<rdar://problem/5231152> better handling of NOLOAD with symlinked dylibs
+
+
+dyld-86.1
+Fix DYLD_SHARED_REGION=private
+update man page
+
+
+dyld-86
+<rdar://problem/4960876> update_dyld_shared_cache fails on @executable_path framework
+<rdar://problem/5213017> [Leopard]: 9A441/442: unable to log in after switching to arabic
+<rdar://problem/5221505> dlopen via CFBundleLoad keeps searching after finding a loadable object
+
+
+dyld-85.2
+<rdar://problem/5202525> MatLab 2007a (7.4) doesn't launch on Leopard9A441
+Never optimize ppc shared cache on intel
+Fix LINKEDIT size in shared cache .map files
+Fix how PIEs are moved to work with NX
+Call pthread_init_keys to work with latest Libc
+
+
+dyld-85.1
+<rdar://problem/5215536> Leopard9A447: Meeting Maker and Microsoft apps will not launch on Intel.
+
+
+dyld-85
+<rdar://problem/5193485> 9A436: Adobe: Photoshop CS3 crashed on pressing Command-C after Command-A
+<rdar://problem/4892382> Use _dyld_initializer
+
+
+dyld-84
+<rdar://problem/5194274> 9A438 dlopen_preflight() corrupts all_image_info list causing Symbolication crashes
+<rdar://problem/5195384> B&I needs an ENV variable to turn off "dyld: ioctl to register dtrace DOF section failed" warnings
+<rdar://problem/4819036> remove support for __image_notify sections
+remove all update_prebinding code
+
+
+dyld-83
+<rdar://problem/4819047> use _simple_dprintf() instead of fprintf()
+remove -progress option from update_dyld_shared_cache
+update_dyld_shared_cache no longer tells rosetta to flush its caches
+<rdar://problem/5110291> update_dyld_shared_cache error message gives an errno value rather than an error string
+<rdar://problem/3968392> dyld interposing doesn't work with dlsym() lookup
+<rdar://problem/5163803> dlopen_preflight() of MH_BUNDLE leaks
+<rdar://problem/5067898&5184629> integrate ImageLoader changes into leopard dyld
+<rdar://problem/5179640> translated (ppc) dyld should not attempt to register DOF sections
+<rdar://problem/5135363> Some dyld library paths are not canonicalized, causing tools using those paths to defenestrate themselves
+
+
+dyld-82.5
+<rdar://problem/5147450> REGR: Leopard9A419: Firefox hangs on launch
+
+
+dyld-82.4
+<rdar://problem/5150283> Leopard9A420: interposing of libMallocDebug or libgmalloc broken
+Fix so problems like <rdar://problem/5149971> are warnings instead of errors
+
+
+dyld-82.3
+<rdar://problem/5148533> 9A420: dyld: ioctl to register dtrace DOF section failed
+
+
+dyld-82.2
+<rdar://problem/5135896> dyld frees string returned by dyld_image_state_change_handler
+<rdar://problem/5133621> better handling than "corrupt binary, library ordinal too big"
+
+
+dyld-82.1
+<rdar://problem/5125295> dyld changes needed to support read-only DOF
+
+
+
+dyld-82
+<rdar://problem/5115360> don't need to hold dyld global lock while running initializers
+<rdar://problem/5094847> dyld leaks when dlopen fails
+<rdar://problem/5128758> dyld leaks two blocks after bundle unload
+
+
+dyld-81
+<rdar://problem/5016782> auto update dyld shared caches if missing or out of date
+
+
+dyld-80.1
+<rdar://problem/5090212> Erronious "unsafe use of @rpath" dyld error
+<rdar://problem/5066570> 9A384: update_dyld_shared_cache fails after ditto'ing matador root with debug info
+<rdar://problem/5093704> Uninitialized ImageLoader->fRegisteredDOF field
+
+
+dyld-80 (Leopard9A400)
+<rdar://problem/4971149> Use new shared region syscalls
+<rdar://problem/5073851> @rpath does not work with -rpath @executable_path/...
+<rdar://problem/5067376> Firefox causes segfault during update_dyld_shared_cache
+
+
+dyld-79.3
+<rdar://problem/4971149> Use new shared region syscalls
+
+dyld-79.2
+<rdar://problem/5073851> @rpath does not work with -rpath @executable_path/...
+
+dyld-79.1 (Leopard9A396)
+fix use of LC_REEXPORTED_DYLIB
+
+
+dyld-79 (Leopard9A392)
+<rdar://problem/5039911> Support Apple PIE (address space randomization)
+<rdar://problem/5055814> update_dyld_shared_cache should warning and not quit if a specified root is missing
+<rdar://problem/5058918> DOF registration needs to switch from /dev/helper to /dev/dtracehelper
+<rdar://problem/5042252> don't error out when a cache line crossing i386 stub cannot be bound
+
+
+dyld-78.2 (Leopard9A387)
+<rdar://problem/5050338> 9A385: Mail (anything using Message.framework) takes a ridiculous amount of time to launch
+
+
+dyld-78.1 (Leopard9A385)
+Fix override of _malloc_lock to be data instead of code
+
+
+dyld-78
+<rdar://problem/5040417> when loading a bundle, dyld is not making a copy of name
+<rdar://problem/5001598> 9A343 KidPix 3 : SpellChecker bundle is not loaded
+<rdar://problem/5028176> dyld cache does not recognize dynamic load of library via symbolic link
+
+
+dyld-77.1
+Back out 4892382 until B&I build fleet has fixed kernel
+
+
+dyld-77
+<rdar://problem/4892382> Use _dyld_initializer
+<rdar://problem/4838967> Look at reduction/elimination of per-framework cost (don't touch __dyld section)
+<rdar://problem/4920999> libdyldapis.a: make initialization as lean as possible
+<rdar://problem/3896792> dyld should malloc never-to-be-freed blocks from its own pool
+<rdar://problem/4980326> Libraries feeding into Libsystem should contain version numbers (libdyldapis)
+Install update_prebinding symlink
+Addend warnings to end of shared cache .map files
+Conditionalize away update_prebinding support
+dladdr() should not remove 's' from "start"
+
+
+dyld-76.2
+<rdar://problem/4987676> hang at boot, Libc changes
+
+dyld-76.1
+<rdar://problem/4979617> x86_64: dyld share cache does not work for AppKit
+
+
+dyld-76
+<rdar://problem/4958744> Rosetta apps crash after update_dyld_shared_cache
+<rdar://problem/4953905> Long-standing typo for "file to short" error from dlopen() / dlerror()
+
+
+dyld-75.1
+Enable ppc shared cache generation on intel machines
+
+
+dyld-75
+<rdar://problem/4931772> 64-byte crossing fast stubs should be bound early to avoid threading issues
+<rdar://problem/4217374> support new intel stub segment that is marked not-writable
+
+
+dyld-74
+<rdar://problem/4893418> register dtrace DOF sections with kernel
+<rdar://problem/4898960> 10.4.9 Regression: Math Kernel crash with TiNovi 8P114
+
+
+dyld-73.2
+<rdar://problem/4889617> Leopard 9A921: Dyld error "lazy pointer not found" loading/running java
+
+
+dyld-73.1 (Leopard9A328)
+<rdar://problem/4883565> 9A326: update_prebinding crashes at end of install
+
+
+dyld-73 (Leopard9A326)
+<rdar://problem/4876600> REGR: 9A322 All Java apps crashing at dyld's misaligned_stack_error
+
+
+dyld-72 (Leopard9A322)
+<rdar://problem/4853532> Maya 8 crashes on launch on Leopard9A309
+<rdar://problem/4791766> ProTools 7.1.1cs1 for Intel hangs on launch on Leopard9A309
+<rdar://problem/4388957> x86 crashes in the binding helper do not have proper backtrace
+
+
+dyld-71 (Leopard9A320)
+<rdar://problem/4824553> inform rosetta of each library in the dyld shared cache
+<rdar://problem/4853825> 9A316: Dreamweaver MX 2004 crashes on launch in dyld's addImage
+
+
+dyld-70 (Leopard9A315)
+support split-seg dylibs built with LC_SEGMENT_SPLIT_INFO
+support --progress option in update_dyld_shared_cache so that installer can run it
+
+
+dyld-69.1 (Leopard9A309)
+<rdar://problem/4826097> 9A305: Firefox 2.0 crashes on launch
+<rdar://problem/4827641> httpd is dying in dyld after libobjc.dylib is unloaded
+
+
+dyld-69 (Leopard9A305)
+<rdar://problem/3532018> ER: dlclose() should be able to unload dylibs
+<rdar://problem/3584130> runtime support for RPATH
+
+
+dyld-68 (Leopard9A296)
+<rdar://problem/4797707> rosetta doesn't work when shared cache is present
+<rdar://problem/4800592> shared cache for 64-bit archs does not work when some dylibs are invalid
+
+
+dyld-67.1 (Leopard9A292)
+<rdar://problem/4754048> support 64-bit programs built with new 10.5 subtype
+
+
+dyld-67
+<rdar://problem/4764143> CrashReporter needs a new way to distinguish fatal dyld errors
+<rdar://problem/4610810> support dlopen(NULL, RTLD_FIRST)
+Move base address of ppc64 dyld to match new memory layout
+Move base address of 64-bit shared caches to match new memory layout
+Move location of shared cache file to /var/db/dyld
+Add support for LC_REEXPORT_DYLIB
+Use shared cache if it exists
+Requires ld64-63.1 or later built dylibs for shared cache generation
+
+
+dyld-66.3 (Leopard9A276)
+<rdar://problem/4742808> dyld fails to build with Libc changes in 4632326
+<rdar://problem/4754048> support 64-bit programs built with new 10.5 subtype
+
+
+dyld-66.2 (Leopard9A260)
+<rdar://problem/4718046> Leopard9A259: Backtraces in crash reports are not getting symbolicated
+<rdar://problem/4714894> dyld should get rosetta process name from standard location
+
+
+dyld-66.1 (Leopard9A259)
+Fix for build breakage with Libc-436
+
+
+dyld-66
+Preliminary shared cache support
+<rdar://problem/4109087> <mach-o/dyld_gdb.h> is in Darwin but not Dev Tools package
+<rdar://problem/4710378> export shared range regions for gdb
+<rdar://problem/4697552> __pthread_tsd_first appears to be initialized too late in dyld
+<rdar://problem/4589305> don't use @executable_path or fallback searching in setuid programs
+
+
+dyld-65.1 (Leopard9A252)
+fix B&I build failure with Libc-435
+
+
+dyld-65 (Leopard9A247)
+<rdar://problem/4653725> jump table entry at end of segment can crash
+<rdar://problem/4644563> Mathematica 5.2 (64-bit MathKernel) always crashes on 9A229
+<rdar://problem/4088447> dlsym man page needs to be more specific about RTLD_DEFAULT
+<rdar://problem/4092461> Change wording in SEARCHING section in dlopen man page
+<rdar://problem/4560992> Man page for dyld has misspelling: cheep
+<rdar://problem/4579459> dyld(3) man page should point to Mach-O Programming Topics URL
+
+
+dyld-64 (Leopard9A224)
+<rdar://problem/4620487> No man page for dlopen_preflight(3)
+<rdar://problem/4363960> dyld lazy binding of fast stubs is not completely thread safe
+<rdar://problem/4628677> remove use of load_shared_file()
+
+
+dyld-63 (Leopard9A215)
+<rdar://problem/4530861> Would like way to quiet dynamic loader
+<rdar://problem/4513256> deprecated old APIs for Leopard
+<rdar://problem/4590713> NSCreateObjectFileImageFromMemory crashes when image is a MH_EXECUTABLE
+
+
+dyld-62.1 (Leopard9A206)
+<rdar://problem/4598215> prebound old stubs failure prevents uTest from running on i386
+
+
+dyld-62 (Leopard9A202)
+<rdar://problem/4589041> an image with an open non-zero base address does not load more efficiently
+<rdar://problem/4590567> Leopard9A190: NSAddImage() crashes when called from x86_64 process
+<rdar://problem/4578484> /usr/lib/libAPSimple.dylib: mmap error
+<rdar://problem/4557971> need to force interposing for rosetta processes
+
+
+dyld-61 (Leopard9A179)
+<rdar://problem/4528739> dyld calls close(-1)
+<rdar://problem/4506173> _stub_binding_helper_interface isn't using movdqa
+<rdar://problem/4548652> dyld tries to mmap 0 size segments and fails with conforming mmap
+<rdar://problem/4536652> Load dyld above 4GB for x86-64
+Move apple parameters on stack when DYLD_ variables are removed
+
+
+dyld-60 (Leopard9A160)
+<rdar://problem/4379896> Suresec #203: dyld environment with suid binaries
+<rdar://problem/4148690> SureSec si#187 linker: environment variables
+<rdar://problem/3915210> print warning message if DYLD_INSERT_LIBRARIES is set (then ignored) for a setuid/setgid program
+<rdar://problem/4359815> dyld's disableIfBadUser() routine can fail for constant strings
+
+
+dyld-59 (Leopard9A156)
+<rdar://problem/4452274> ER: dlopen_preflight()
+
+
+dyld-58 (Leopard9A154)
+<rdar://problem/3827070> implement RTLD_SELF
+<rdar://problem/4045952> better handling of open() errors
+<rdar://problem/4198200> would like dlopen(RTLD_FIRST) so that dlsym variant that does not search dependent libraries
+<rdar://problem/4508801> dyld needs to adopt to Unix conformance changes
+<rdar://problem/4507650> Crash on Leopard9A146 when GC rejects loading a library on Intel
+
+
+dyld-57 (Leopard9A144)
+<rdar://problem/4423668> pthread tsd entries doubly owned by DYLD and Libsystem... (Leopard)
+<rdar://problem/4492351> dyld should automatically stop using the shared region if unavailable
+<rdar://problem/4494723> If instantiateFromLoadedImage fails, dyld crashes
+<rdar://problem/4494725> isCompatibleMachO needs to know about x86-64
+
+
+dyld-56 (Leopard9A140)
+<rdar://problem/3908479> 64-bit dyld should load at around the last 4G - not in the first 4G
+<rdar://problem/4486559> 64 bit: app crashes immediately if -pagezero_size >= 0x0ffffffff
+<rdar://problem/4486804> dyld needs to build for x86-64
+<rdar://problem/4149233> dyld_debug API shim has leak
+<rdar://problem/4490848> dyld does not slide properly on Intel
+
+
+dyld-55 (Leopard9A138)
+<rdar://problem/4430145> dlopen() should fail if bundle has objc code incompatible with runtime environment
+<rdar://problem/4340954> libdyld: make non-POSIX header definitions visible when _POSIX_C_SOURCE is defined
+<rdar://problem/4393607> A flat_namespace image with a reference to an internal private_extern should resolve immediately
+<rdar://problem/4401777> dlopen() man page is missing RTLD_NOLOAD and RTLD_NODELETE
+<rdar://problem/4427324> _CFExecutableLinkedOnOrAfter() fails on 64 bit
+<rdar://problem/4442283> dyld needs to support x86-64
+
+
+dyld-54 (Leopard9A80)
+<rdar://problem/4030730> remove ppc64 workarounds for fixed bugs
+<rdar://problem/4051922> Memory error in removePathWithPrefix()
+<rdar://problem/4258921> dyld does not properly swap CPU subtype from fat file header
+<rdar://problem/4361806> dyld does not compile for open source
+<rdar://problem/4363188> ADOBE XCODE 2.2: ZeroLink can cause wrong typeinfos to be used
+Sync with Chardonnay (except for 4313830 and 4215516)
+
+
+dyld-53 (Leopard9A42)
+<rdar://problem/4254657> Add -fno-exceptions to Release target of libdyld
+<rdar://problem/4326451> Wrong number of seconds reported by DYLD_PRINT_STATISTICS on Intel
+
+
+dyld-52 (Leopard9Axxx)
+<rdar://problem/4172797> dyld changes for new libstdc++ project
+
+
+dyld-51 (Clueless)
+<rdar://problem/3866740> STD:VSX: dlclose() should return non-zero value on failure.
+<rdar://problem/3944469> STD:BUILD: dyld references non-conforming member name for PPC64
+<rdar://problem/4116234> The gdb list of images should be updated before dyld bases and binds each image
+<rdar://problem/3916854> interposing does not handle stacking/nesting of interposing functions
+<rdar://problem/4090063> use of DYLD_INTERPOSE() causes compiler warnings with -std=c99 -pedantic
+<rdar://problem/3992272> SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371
+
+dyld-50 (Leopard9Axxx)
+Convert to build with gcc-4.0
+<rdar://problem/3992272> SWB: dyld-32 fails to link using 4.0 compiler (gcc-4042) on Tiger8A371
+
+----------------------------------
+
+
+
+dyld-46.16 (Mac OS X 10.4.11)
+<rdar://problem/5146059&5334400> raise bail out limit in update_prebinding to 100 errors
+
+dyld-46.15
+<rdar://problem/5334280> [SUIncaSoho] update_prebinding can only handle 2MB of ppc unprebound dylibs on intel
+<rdar://problem/5146059&5334400> update_prebinding fails if a prebound dylib depends on a non-prebound dylib
+
+dyld-46.14
+<rdar://problem/4814545&5260830> prebinding zeroes out files if an error occurs (such as no vm space left)
+<rdar://problem/4948045&5257758> Rare & unknown root cause: Corruption of Kerberos framework during SU
+
+dyld-46.13
+<rdar://problem/4975286> dyld crashes starting threaded program
+<rdar://problem/5050570> 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state
+<rdar://problem/5116499> 10.4.9 Regression: SuTiNovi8P132: update_prebinding never reaches steady state
+<rdar://problem/5160205> [SUTiSoHo] update_prebinding crashes when a weak linked dylib is missing
+<rdar://problem/5165777> [SUIncaSoHo] update_prebinding crashes when a weak linked dylib is missing
+
+dyld-46.12
+<rdar://problem/4898960> 10.4.9 Regression: Math Kernel crash with TiNovi 8P114
+
+dyld-46.11
+<rdar://problem/4642940> dyld's x86_64 support should be open source
+<rdar://problem/4604221> 10.4.x: an image with an open non-zero base address does not load more efficiently
+<rdar://problem/4864380> [SUTiNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately
+<rdar://problem/4870982> [SUTiNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7
+<rdar://problem/4765099> [SUIncaNovi] 10.4.8 regression: ppc X program segmentation fault in 10.4.8, worked in 10.4.7
+<rdar://problem/4864373> [SUIncaNovi] A flat_namespace image with a reference to an internal private_extern should resolve immediately
+
+dyld-46.10
+<rdar://problem/4787033> dyld-46.9 fails to build in Nicoya
+
+dyld-46.9 (Inca8K...)
+<rdar://problem/4653725> jump table entry at end of segment can crash
+
+dyld-46.8 (Inca8K1073)
+<rdar://problem/4645490> Mathematica 5.2 (64-bit MathKernel) always crashes on Inca
+
+dyld-46.7 (Inca8K1072)
+<rdar://problem/4622201> dyld lazy binding of fast stubs is not completely thread safe
+
+dyld-46.6 (Inca8K1061)
+<rdar://problem/4607261> Inca: don't write warning to stderr for setuid binaries
+
+dyld-46.5 (Inca8K1059)
+<rdar://problem/4598215> prebound old stubs failure prevents uTest from running on i386
+
+dyld-46.4 (Inca8K1057)
+<rdar://problem/4590567> NSAddImage() crashes when called from x86_64 process
+<rdar://problem/4589041> an image with an open non-zero base address does not load more efficiently
+
+dyld-46.3 (Inca8K1054)
+<rdar://problem/4557971> need to force interposing for rosetta processes
+re-enable setuid security fixes for 4525062 and 4525053
+
+dyld-46.2 (Inca8K1046)
+<rdar://problem/4551683> Adobe CS2 no longer launches
+<rdar://problem/4536652> Load dyld above 4GB for x86-64
+
+dyld-46.1 (Inca8K1040)
+rdar://problem/4538177 dyld does not slide on x86_64
+
+dyld-46 (Inca...)
+re-enable x86_64
+
+
+dyld-45.3 (SUSecurity )
+<rdar://problem/4607244> *SecUpd: Chardonnay* don't write warning to stderr for setuid binaries
+<rdar://problem/4607243> *SecUpd: Tiger* don't write warning to stderr for setuid binaries
+
+dyld-45.2 (SUSecurity )
+<rdar://problem/4525062> *SecUpd: Chardonnay* SureSec si#187 remove all DYLD_ env vars for setuid binaries
+<rdar://problem/4148690> *SecUpd: Tiger* SureSec si#187 remove all DYLD_ env vars for setuid binaries
+<rdar://problem/4525053> *SecUpd: Chardonnay* Suresec #203: don't use $HOME with suid binaries
+<rdar://problem/4379896> *SecUpd: Tiger* Suresec #203: don't use $HOME with suid binaries
+
+
+dyld-45.1 (SUTiLondon...)
+back out <rdar://problem/4379896> Suresec #203: dyld environment with suid binaries [SUTi]
+
+
+dyld-45 (SUTiLondon...)
+<rdar://problem/4522929> sync all 10.4.x dyld trains
+<rdar://problem/4320078> dyld fix for gcc-3.3 C++ needs to get in SU
+<rdar://problem/4501854> 64-bit dlopen crashes when opening fat bundle
+<rdar://problem/4148690> SureSec si#187 linker: environment variables [SUTi]
+<rdar://problem/4379896> Suresec #203: dyld environment with suid binaries [SUTi]
+<rdar://problem/4525062> SureSec si#187 linker: environment variables [SUChard]
+<rdar://problem/4525053> Suresec #203: dyld environment with suid binaries [SUChard]
+
+dyld-44.23 (Inca8...)
+<rdar://problem/4498577> Crash using Core Image under Rosetta running InDesign CS2 w/ Magma Effects
+
+dyld-44.22 (Inca8K1030)
+<rdar://problem/4498515> Stub binding helper changes for FP args for x86-64
+
+dyld-44.21 (Inca8K1030)
+<rdar://problem/4497724> printf doesn't work for x86-64
+
+dyld-44.20 (Inca8K1029)
+<rdar://problem/4494725> isCompatibleMachO needs to know about x86-64
+
+dyld-44.19 (Inca8J1028)
+two small x86_64 fixes
+
+dyld-44.18 (Inca8J1027)
+<rdar://problem/4442283> dyld needs to support x86-64
+
+dyld-44.17 (Chardonnay8G1152)
+<rdar://problem/4381131> prebound fast stubs not ignored for flat_namespace dylibs
+
+dyld-44.16 (Chardonnay8G1141)
+<rdar://problem/4360528> Sherlock often crashes in dyld::bindLazySymbol on launch
+
+dyld-44.15 (Chardonnay8G1137)
+<rdar://problem/4356145> no apps can launch with /usr/lib/libMallocDebug.A.dylib on 8G1133
+
+dyld-44.14 (Chardonnay8F1110)
+<rdar://problem/4321820> System Integrity: changes needed for dyld
+
+dyld-44.13 (Chardonnay8F1108)
+<rdar://problem/4313830> pthread tsd entries doubly owned by DYLD and Libsystem... (Chardonnay)
+
+dyld-44.12 (Chardonnay8F1108)
+<rdar://problem/4318081> never pass shared_region_map_file_np() a zero-length region
+
+dyld-44.11 (Chardonnay8F1104)
+<rdar://problem/4303000> dyld launch code should special case if there is only one prebound image with weak exports
+
+dyld-44.10 (Chardonnay8F1100)
+<rdar://problem/4296378> dyld fails to link with Libc-391.1.13
+
+dyld-44.9 (Chardonnay8F1093)
+<rdar://problem/4212667> XCode2.1 + gcc 3.3 + C++ exception + Bundle Bug
+<rdar://problem/4278103> low disk space code path executed with 44GB free
+
+dyld-44.8 (Chardonnay8F1079)
+<rdar://problem/4215516> dyld lazy binding code should use movdqa
+
+dyld-44.7 (Chardonnay8B1072)
+<rdar://problem/4247155> fix for rosetta crashes
+
+dyld-44.6 (Chardonnay8B1072)
+<rdar://problem/4179957> Optimizing system should only progress once
+
+dyld-44.5 (Chardonnay8B1052)
+<rdar://problem/4164559> New intel stub support
+
+dyld-44.4 (Chardonnay8B1051)
+<rdar://problem/4178195> Leopard 9A14: Finder crashes burning a CD
+<rdar://problem/4186248> dyld lazy binding code needs to save/restore all possible register parameters
+<rdar://problem/4172797> use new libstdc++-static
+
+dyld-44.3 (Chardonnay8B1051)
+<rdar://problem/4189498> dyld should recognize byte-swapped Mach-O files
+<rdar://problem/4194105> dyld should only update prebound external relocations if they change
+
+dyld-44.2 (SUTiDenver8F10) [Mac OS X 10.4.3]
+<rdar://problem/4189935> Tiger breaks NSCreateObjectFileImageFromMemory with fat Mach-O
+<rdar://problem/4139432> dyld does not load libraries correctly if matching install_name in /usr/lib
+<rdar://problem/4153431> CrashTracer: ..269 crashes at com.adobe.Acrobat.framework: RunAcrobat + 424
+
+dyld-44.1 (Chardonnay)
+<rdar://problem/4132378> __attribute__ ((regparm (3), stdcall)) doesn't work for inter-image calls
+<rdar://problem/4111112> dyld should automatically set DYLD_SHARED_REGION to avoid
+
+dyld-44 (Chardonnay)
+<rdar://problem/4170213> merge SUTiCambridge dyld and Karma dyld into Chardonnay
+
+
+dyld-43.1 (SUTiCambridge8C20) [Mac OS X 10.4.2]
+Update open source APSL headers
+<rdar://problem/4120834> update_prebinding should gracefully handle low disk space
+<rdar://problem/4108674> prebinding should not change n_value of .obj_class_name symbols
+<rdar://problem/4057081> dyld gets into infinite loop with dlsym if dylib dependencies contain loops
+<rdar://problem/4072295> FilesBuster crashed in dyld
+<rdar://problem/4104022> DYLD_ROOT_PATH crashes program if any component does not start with /
+<rdar://problem/4104027> dyld writes past end of buffer when checking environment variables
+<rdar://problem/4106921> dyld_image_removing notification never sent
+<rdar://problem/4121907> ANN: DR020
+
+
+dyld-43 (Tiger8A428) [Mac OS X 10.4.0]
+rdar://problem/4067311 PACE protected Mach-O apps crash under Tiger 8a420
+
+
+dyld-42 (Tiger8A420)
+rdar://problem/4058724 FileMaker JDBC extension does not work in Tiger
+
+
+dyld-41 (Tiger8A417)
+rdar://problem/4047633 Adobe Photoshop CS2: Scripting Save for Web runs out of memory unexpectedly when compared to 10.3.8.
+
+
+dyld-40 (Tiger8A413)
+rdar://problem/4047391 dyld no longer follow dependent libraries using dlopen
+
+
+dyld-39 (Tiger8A406)
+rdar://problem/4034570 DT P1: MATLAB R14sp2 does not run on Tiger
+rdar://problem/4028274 DT P1: GLSLShowpieces crashes when built and run
+
+
+dyld-38 (Tiger8A402)
+rdar://problem/3820219 Tiger + MOTU Digital Performer + hit play = Digital Performer crashes
+rdar://problem/3978682 If an excutable & a framework with the same base name are in the same folder, you get a dyld error if you use full path
+rdar://problem/3987135 MATLAB unresolved symbol __XEditResPutWidgetInfo on Tiger
+rdar://problem/4027813 dlsym man page documents unsupported RTDL_SELF
+
+
+dyld-37 (Tiger8A399)
+rdar://problem/4001668 Safari hang inside CFBundleDYLDGetSymbolByNameWithSearch in Flash plug-in upon opening www.espn.com
+rdar://problem/3853454 dyld needs to call sys_icache_invalidate() after instruction fix-ups
+rdar://problem/3984074 Soldier of Fortune II crashes at start of gameplay on Tiger8A36
+rdar://problem/4008399 Malicious user can set Tiger dyld fallback paths in setuid process
+rdar://problem/4021002 Aliens vs Predator II with latest update does not run
+
+
+dyld-36 (Tiger8A393)
+rdar://problem/3970385 [Tiger] 8A323: Aliens VS Predator 2 Freezes On Launch
+rdar://problem/3839120 _dyld_get_image_header_containing_address returning NULL when it shouldn't
+rdar://problem/3925105 update_prebinding crashes on /usr/lib/libnetsnmptrapd.5.dylib
+
+
+dyld-35 (Tiger8A384)
+rdar://problem/3984074 Soldier of Fortune II crashes at start of gameplay on Tiger8A367
+rdar://problem/4003637 Typo blocks support of -init for 64-bits
+rdar://problem/4003891 improve mmap() failure error msg
+
+
+dyld-34 (Tiger8A381)
+rdar://problem/3976215 dlopen() should look for a library with matching name and architecture
+rdar://problem/3978682 executable and dylibs can be confused
+rdar://problem/3819111 dlopen() ignores LD_LIBRARY_PATH
+rdar://problem/3956709 Insufficient documentation for dlopen
+
+
+dyld-33 (Tiger8A379)
+rdar://problem/3941826 8A340: Tron 2.0 does not launch
+rdar://problem/3848965 James Bond 007 Nightfire fails to launch
+rdar://problem/3947513 No One Lives Forever 2 crashes on Quit on Tiger8A347
+rdar://problem/3779999 Spyhunter crashes upon launch on Tiger8A244
+
+
+dyld-32 (Tiger8A367)
+rdar://problem/3974486 PowerMail launch fails: weak linking of library but not symbols
+rdar://problem/3974797 can update_prebinding only complain about stuff I actually have installed?
+rdar://problem/3979715 synchronizing attribute name with section name
+
+
+dyld-31 (Tiger8A362)
+rdar://problem/3958479 Third party "crash reporter" app backtraces have no symbols for our libraries/APIs
+rdar://problem/3966025 add DYLD_INTERPOSE macro to an apple internal header
+rdar://problem/3968283 For interposing support section-by-type and section-by-name
+
+
+dyld-30 (Tiger8A357)
+rdar://problem/3947090 objc runtime / two-level namespace crash when using new interposing libMallocDebug or libgmalloc
+
+
+dyld-29 (Tiger8A356)
+rdar://problem/3960729 update_prebinding needs to fflush() every output line
+rdar://problem/3960657 Why are my crashreporter logs all useless?
+
+
+dyld-28 (Tiger8A354)
+rdar://problem/3510780 _dyld_get_image_header_containing_address man page is wrong
+rdar://problem/3798074 STD: dlclose() does not unload bundles
+rdar://problem/3882857 dyld no longer finds framework file if not in Framework hierarchy
+rdar://problem/3898206 dlopen() does not support library searching as linkage at launch does
+rdar://problem/3921479 dyld(1) should not document unimplemented env vars
+rdar://problem/3935714 Support RTLD_NODELETE
+rdar://problem/3942919 can't use _debug libSystem
+
+
+dyld-27 (Tiger8A350)
+rdar://problem/3902088 update_prebinding needs to provide progress information
+
+
+dyld-26 (Tiger8A348)
+rdar://problem/3943033 hang upon boot, permissions and startup thrash
+
+
+dyld-25 (Tiger8A347)
+rdar://problem/3916220 Main executable unmapped
+rdar://problem/3812732 Microsoft Error Reporting crashes on Tiger
+rdar://problem/3943349 dyld project should install mach-o/dyld_debug.h
+rdar://problem/3943546 mach-o/dyld_debug.h should be deprecated
+rdar://problem/3933738 use getsectdatafromheader_64
+
+
+dyld-24 (Tiger8A345)
+rdar://problem/3941688 update_prebinding needs a --dry-run option
+
+
+dyld-23
+rdar://problem/3799069 Need coalescing across dylibs
+rdar://problem/3859973 problem with weaklink using darwine
+rdar://problem/3938167 dyld does not work with XLF generated binaries and provided libraries
+rdar://problem/3935377 STD: dyld needs to include sys/time.h and sys/types.h
+rdar://problem/3930361 STD: dyld must create a stub for ___fegetfltrounds
+rdar://problem/3934712 STD:VSX: more dlfcn.h namespace issues
+
+
+dyld-22.5 (Tiger8A340)
+rdar://problem/3788633 MatLab 7.0 fails to launch on Tiger8A246
+rdar://problem/3919674 prebound flat-namespace libraries are bound wrong
+
+
+dyld-22.4
+rdar://problem/3915914 make update_prebinding more robust
+
+
+dyld-22.3 (Tiger8A333)
+rdar://problem/3920720 dyld missing symbols because Xcode not add -fvisibility=hidden
+
+
+dyld-22.2 (Tiger8A330)
+rdar://problem/3909873 Transmit.app crashes with symbol not found
+
+
+dyld-22.1
+rdar://problem/3908248 Crash in apps when launched from MallocDebug (BlockMove symbol not found if DYLD_FORCE_FLAT_NAMESPACE is set)
+
+
+dyld-22 (Tiger8A325)
+rdar://problem/3903866 reduce LINKEDIT page usage by better use of two-level hints
+rdar://problem/3884004 Libraries can be half-baked if an error occurs during their first use
+rdar://problem/3899047 interposing doesn't work on 8A317 with dyld-21
+rdar://problem/3514720 Adobe bundle kernel panics system
+
+
+dyld-21 (Tiger8A322)
+rdar://problem/3745562 Support two-level interposing with insert libraries (malloc-debug)
+rdar://problem/3892061 8A316: Selecting any application in Finder in the column view crashes finder
+rdar://problem/3894540 DYLD_PRINT_SEGMENTS no longer works on 8A317
+
+
+dyld-20 (Tiger8A317)
+rdar://problem/32957877 Support @loader_path in dylib commands
+rdar://problem/33837173 need SPI to set fallback symbol lookup
+rdar://problem/33891778 dyld (__DATA,__dyld) function pointers should drift as little as possible
+Fix issue with new prebinding overwriting symlinks
+
+
+dyld-19 (Tiger8A315)
+rdar://problem/3823664 dyld reports corrupt executable
+rdar://problem/3847571 dyld submission number should be embedded in dyld
+rdar://problem/3865141 dyld_all_image_infos should contain bit that says if process is using the shared region
+rdar://problem/3884103 dyld needs to use -msoft-float for ppc64
+rdar://problem/3886337 PPC_RELOC_PB_LA_PTR not recognized by ppc64
+Clean up/document dyld-gdb interface
+
+
+dyld-18.3 (prebinding sideworld build)
+prebinding enhancements
+
+dyld-18.2 (Tiger8A306)
+rdar://problem/3782982 Fix for Macromedia apps (Flash 7.2)
+
+dyld-18.1
+rdar://problem/3864644 DVD player crash (loading memory based bundle)
+
+dyld-18 (Tiger8A303)
+rdar://problem/3866877 STD:VSX dlsym() faults when passed a bad handle.
+rdar://problem/3862043 typo in dyld function name
+rdar://problem/3857000 dyld should limit its exported symbols
+rdar://problem/3835208 want better error message for incompatible libraries
+dyld now built with dead-code-stripping
+better launch performance when hundreds of libraries are used
+more bug fixes in update_prebinding in dyld
+
+
+dyld-17.1 (Tiger8A301)
+rdar://problem/3672757 initial implementation of update_prebinding in dyld
+rdar://problem/3847376 dyld does not slide itself properly (partial fix)
+rdar://problem/3843028 STD: make dlfcn.h posix compliant
+rdar://problem/3856182 STD: add includes
+rdar://problem/3782982 infrastructure work on compatibility for Macromedia apps
+Other 64-bit tweaks
+
+
+dyld-16.1 (Tiger8A296)
+rdar://problem/3768530 dyld should adopt shared_region_map_file_np()
+
+
+dyld-15 (Gordian 64-bit side world build only)
+rdar://problem/3834744 64-bit dyld needs to handle mh->cputype != host_info cputype
+Other 64-bit clean ups
+
+
+dyld-14 (Tiger8A280)
+rdar://problem/3811777 Deadlock in dyld code, seen in Merlin and Mail
+rdar://problem/3793075 Update to fix: DVD Player crashes at launch with disc in drive
+rdar://problem/3830560 Don't let gcc-3.5 optimize away send_event
+rdar://problem/3826169 Update dlfcn.h header to Apple header and acknowledge Peter and Jorge
+rdar://problem/3793861 Update dlopen(3) man page to reflect new implementation
+rdar://problem/3559013 libdyld.a needs to build for ppc64
+Added DYLD_PRINT_OPTS
+Added DYLD_PRINT_ENV
+Deprecated 10 APIs
+
+
+dyld-13 (Gordian 64-bit side world build only)
+rdar://problem/3560664 Add ppc64 support
+rdar://problem/3819144 Opening PDF in Safari crashes
+rdar://problem/3793861 Update dlopen man pages
+rdar://problem/3765271 Build with gcc-3.5
+rdar://problem/3762685 Make own prototype for task_self_trap()
+rdar://problem/3799467 Mozilla tries to open a dylib using a bundle API
+rdar://problem/3812263 Add dyld SPI so Shark can interpose lazy pointer lookup
+Added emacs major-mode and tab-width directives
+
+
+dyld-12.4 (Tiger8A271)
+tweak so dyld can use libc.a built with long double support
+
+
+dyld-12.3 (no-build)
+rdar://problem/3765271 switch dyld to build with gcc-3.5
+
+
+dyld-12.2 (Tiger8A265)
+rdar://problem/3793075 DVD Player crashes at launch with disc in drive
+
+
+dyld-12.1 (Tiger8A255)
+rdar://problem/3749360 a flat lookup needs to search everywhere and not short-circuit to own image
+
+
+dyld-12 (Tiger8A231)
+rdar://problem/3751226 make dyld thread safe (libdyld.a should come from new dyld project)
+rdar://problem/3654650 integrate dlopen() and friends into dyld
+
+
+dyld-11.3 (Tiger8A225)
+rdar://problem/3751226 NSAddImage() with leaf name doesn't use fallback path
+
+
+dyld-11.1 (Tiger8A223)
+rdar://problem/3749251 NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED implies NSADDIMAGE_OPTION_RETURN_ON_ERROR"
+
+
+dyld-11 (Tiger8A220)
+rdar://problem/3684168 prevent DYLD_LIBRARY_PATH from causing circular reference when two dylib have same leaf name
+rdar://problem/3698212 implement _dyld_launched_prebound()
+rdar://problem/3696924 suppport frameworks without symlink to current version
+rdar://problem/3692136 Support DYLD_PRINT_LIBRARIES_POST_LAUNCH
+rdar://problem/3685517 make find-image-for-address faster via caching
+rdar://problem/3661976 -force_flat_namespace should disable prebinding
+rdar://problem/3702311 make dyld's __TEXT read-only
+rdar://problem/3669059 do cpu sub-type checking on thin files
+rdar://problem/3696002 Support C++ vague linkage that resolves internally
+rdar://problem/3725847 run initializers in inserted libraries
+rdar://problem/3731063 pass arc/argv to initializers
+rdar://problem/3731100 don't write on __dyld section unless necessary
+rdar://problem/3731633 use mmap() instead of map_fd()
+rdar://problem/3676934 don't double read first page of images, use pread()
+rdar://problem/3725372 ignore environment variables for setuid binaries
+
+
+dyld-10.2 (Tiger8A157)
+rdar://problem/3668765 Macromedia apps don't launch
+
+
+dyld-10.1 (Tiger8A156)
+rdar://problem/3691952 Fix-n-continue broke in Objective-C
+
+
+dyld-10 (Tiger8A148)
+rdar://problem/3686995 implement dyld_call_module_initializers_for_dylib and do parameter sanity checking of module parameters
+rdar://problem/3674139 Make @executable_path work when main executable is a symlink
+rdar://problem/3688719 Support CW built binaries built with -data_before
+
+
+dyld-9
+rdar://problem/3682744 GoLive crash (NSIsSymbolDefinedWithHint should try harder)
+rdar://problem/3660691 iTunes crash with partial plugin
+rdar://problem/3684167 DYLD_IMAGE_SUFFIX broke
+rdar://problem/3672670 Fix uninitialized variable in objc hook
+
+
+dyld-8 (Tiger8A144)
+rdar://problem/3680627 handle weaklib when prebound
+rdar://problem/3672670 new hook for objc
+
+
+dyld-7 (Tiger8A141)
+rdar://problem/3669059 Support cpu-sub-type selection
+rdar://problem/3675131 allow text relocations
+rdar://problem/3675614 fix lazy pointer usage in termination routines
+rdar://problem/3673658 Allow NSUnLinkModule to be called with NULL
+
+
+dyld-6 (Tiger8A139)
+rdar://problem/3649313 clean up <mach-o/dyld.h>
+rdar://problem/3661976 support MH_FORCE_FLAT
+rdar://problem/3659666 DYLD_FORCE_FLAT_NAMESPACE should disable prebinding
+Better error reporting
+Faster flat namespace lookups
+Better implementation of NSLinkEditError
+
+
+dyld-5 (Tiger8A135)
+rdar://problem/3665738 fix binding of private_extern within multi-module libs
+rdar://problem/3667763 use hints supplied in APIs
+Set error_string for CrashReporter
+Better error message when library can't be found
+Properly use ZeroLink bundle notifier
+
+
+dyld-4 (Tiger8A133)
+rdar://problem/3663433 allmemory shows 8000 pages are missing
+
+
+dyld-3
+rdar://problem/3659408 Proper searching in umbrellas
+rdar://problem/3657040 Better error messages when symbols not found
+rdar://problem/3657197 Add ~/Library/Frameworks to fallback path
+Properly use DYLD_IMAG_SUFFIX
+Initial CrashReporter support
+
+
+dyld-2 (Tiger8A132)
+Support: NSNameOfSymbol, NSModuleForSymbol, NSLibraryNameForModule, and NSMakePrivateModulePublic
+Add more functionality to DYLD_IGNORE_PREBINDING environment variable
+
+
+dyld-1
+Initial submission of dyld rewrite.
-.Dd Aug 28, 2008
+.Dd Nov 7, 2011
.Os
.Dt DLOPEN 3
.Sh NAME
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.
.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
archiveVersion = 1;
classes = {
};
- objectVersion = 45;
+ objectVersion = 46;
objects = {
/* Begin PBXAggregateTarget section */
buildPhases = (
F908135111D3ED9000626CC1 /* usr|include|mach-o */,
F908137011D3FB5000626CC1 /* usr|include */,
+ F9C69EFC14EC8AB8009CAE2E /* usr|local|include */,
F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */; };
F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */; };
F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */; };
- F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9B0912811F11D3400096D49 /* dsc_slider.cpp */; };
- F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9B0913811F11DAB00096D49 /* dsc_slider.h */; };
F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
+ F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */ = {isa = PBXBuildFile; fileRef = F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */; };
F9CE307A1208F1B50098B590 /* dsc_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CE30781208F1B50098B590 /* dsc_extractor.cpp */; };
F9CE307B1208F1C60098B590 /* dsc_extractor.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9CE30791208F1B50098B590 /* dsc_extractor.h */; };
+ F9D1001814D8D13D00099D91 /* dsc_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CE30781208F1B50098B590 /* dsc_extractor.cpp */; };
+ F9D1001D14D8D19500099D91 /* dsc_iterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */; };
F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */; };
+ F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */ = {isa = PBXBuildFile; fileRef = F9D49CCB1458B95200F86ADD /* start_glue.s */; };
F9ED4CD60630A7F100DF4E74 /* dyld_gdb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */; };
F9ED4CD70630A7F100DF4E74 /* dyld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC70630A7F100DF4E74 /* dyld.cpp */; };
F9ED4CD90630A7F100DF4E74 /* dyldAPIs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC90630A7F100DF4E74 /* dyldAPIs.cpp */; };
remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
remoteInfo = libdsc;
};
+ F9D1004614D8D91100099D91 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F9D1001114D8D0BA00099D91;
+ remoteInfo = dsc_extractor;
+ };
F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
name = "usr|local|include|mach-o";
runOnlyForDeploymentPostprocessing = 1;
};
- F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */ = {
+ F9C69EFC14EC8AB8009CAE2E /* usr|local|include */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "usr/local/include/mach-o";
+ dstPath = /usr/local/include;
dstSubfolderSpec = 0;
files = (
- F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */,
+ F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */,
);
- name = "usr|local|include|mach-o";
+ name = "usr|local|include";
runOnlyForDeploymentPostprocessing = 1;
};
F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
F9AB709D0BA75730002F6068 /* dyldLibSystemInterface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyldLibSystemInterface.h; path = src/dyldLibSystemInterface.h; sourceTree = "<group>"; };
F9AC7E930B7BB67700FEB38B /* version.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = BUILT_PRODUCTS_DIR; };
F9B01E3D0739ABDE00CF981B /* dyld.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld.exp; path = src/dyld.exp; sourceTree = SOURCE_ROOT; };
- F9B0912311F11D1600096D49 /* libdsc_slider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdsc_slider.a; sourceTree = BUILT_PRODUCTS_DIR; };
- F9B0912811F11D3400096D49 /* dsc_slider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_slider.cpp; sourceTree = "<group>"; };
- F9B0913811F11DAB00096D49 /* dsc_slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_slider.h; sourceTree = "<group>"; };
+ F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-shared-cache.h"; path = "include/objc-shared-cache.h"; sourceTree = "<group>"; };
F9CE30781208F1B50098B590 /* dsc_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_extractor.cpp; sourceTree = "<group>"; };
F9CE30791208F1B50098B590 /* dsc_extractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_extractor.h; sourceTree = "<group>"; };
+ F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = dsc_extractor.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; path = update_dyld_shared_cache.1; sourceTree = "<group>"; };
+ F9D49CCB1458B95200F86ADD /* start_glue.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = start_glue.s; path = src/start_glue.s; sourceTree = "<group>"; };
F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = dlopen_preflight.3; sourceTree = "<group>"; };
F9ED4C980630A76000DF4E74 /* dyld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyld; sourceTree = BUILT_PRODUCTS_DIR; };
F9ED4C9F0630A76B00DF4E74 /* libdyld.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdyld.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
);
runOnlyForDeploymentPostprocessing = 0;
};
+ F9D1001014D8D0BA00099D91 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */,
F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */,
F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */,
- F9B0912811F11D3400096D49 /* dsc_slider.cpp */,
- F9B0913811F11DAB00096D49 /* dsc_slider.h */,
F9CE30781208F1B50098B590 /* dsc_extractor.cpp */,
F9CE30791208F1B50098B590 /* dsc_extractor.h */,
F99B8E620FEC11B400701838 /* dyld_shared_cache_util.cpp */,
F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
F99B8E670FEC121100701838 /* dyld_shared_cache_util */,
- F9B0912311F11D1600096D49 /* libdsc_slider.a */,
+ F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */,
);
name = Products;
sourceTree = "<group>";
F9ED4CCD0630A7F100DF4E74 /* dyldLock.h */,
F9ED4CCE0630A7F100DF4E74 /* dyldNew.cpp */,
F9ED4CCF0630A7F100DF4E74 /* dyldStartup.s */,
+ F9D49CCB1458B95200F86ADD /* start_glue.s */,
F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */,
F9ED4CD00630A7F100DF4E74 /* glue.c */,
F9ED4CD10630A7F100DF4E74 /* ImageLoader.cpp */,
F939F219078F1A2100AC144F /* dyld_debug.h */,
F9ED4CEA0630A80600DF4E74 /* dyld.h */,
F99EE6AE06B48D4200BF1992 /* dlfcn.h */,
+ F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */,
);
name = include;
sourceTree = "<group>";
};
/* End PBXGroup section */
+/* Begin PBXHeadersBuildPhase section */
+ F9D1000E14D8D0BA00099D91 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
/* Begin PBXNativeTarget section */
F93937310A94FAF700070A07 /* update_dyld_shared_cache */ = {
isa = PBXNativeTarget;
dependencies = (
F99B8EA00FEC195800701838 /* PBXTargetDependency */,
F9CE330B120F40EA0098B590 /* PBXTargetDependency */,
+ F9D1004714D8D91100099D91 /* PBXTargetDependency */,
);
name = update_dyld_shared_cache;
productName = update_dyld_shared_cache;
productReference = F99B8E670FEC121100701838 /* dyld_shared_cache_util */;
productType = "com.apple.product-type.tool";
};
- F9B0912211F11D1600096D49 /* libdsc_slider */ = {
+ F9D1001114D8D0BA00099D91 /* dsc_extractor */ = {
isa = PBXNativeTarget;
- buildConfigurationList = F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */;
+ buildConfigurationList = F9D1001714D8D0F100099D91 /* Build configuration list for PBXNativeTarget "dsc_extractor" */;
buildPhases = (
- F9B0912011F11D1600096D49 /* Sources */,
- F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */,
+ F9D1000E14D8D0BA00099D91 /* Headers */,
+ F9D1000F14D8D0BA00099D91 /* Sources */,
+ F9D1001014D8D0BA00099D91 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
- name = libdsc_slider;
- productName = libdsc_slider;
- productReference = F9B0912311F11D1600096D49 /* libdsc_slider.a */;
- productType = "com.apple.product-type.library.static";
+ name = dsc_extractor;
+ productName = dsc_extractor;
+ productReference = F9D1001214D8D0BA00099D91 /* dsc_extractor.bundle */;
+ productType = "com.apple.product-type.library.dynamic";
};
F9ED4C970630A76000DF4E74 /* dyld */ = {
isa = PBXNativeTarget;
/* Begin PBXProject section */
F9ED4C8B0630A72300DF4E74 /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0440;
+ };
buildConfigurationList = F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */;
- compatibilityVersion = "Xcode 3.1";
+ compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
F9F2A5580F7AEE9800B7C9EB /* libdsc */,
F99B8E550FEC10F600701838 /* dyld_shared_cache_util */,
- F9B0912211F11D1600096D49 /* libdsc_slider */,
+ F9D1001114D8D0BA00099D91 /* dsc_extractor */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n";
+ shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n\nif [ -n \"${RC_PURPLE}\" ]\nthen\n mkdir -p \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/lib\"\n mv \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/local/lib/dsc_extractor.bundle\" \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle\"\nfi";
showEnvVarsInLog = 0;
};
F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
);
runOnlyForDeploymentPostprocessing = 0;
};
- F9B0912011F11D1600096D49 /* Sources */ = {
+ F9D1000F14D8D0BA00099D91 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */,
+ F9D1001814D8D13D00099D91 /* dsc_extractor.cpp in Sources */,
+ F9D1001D14D8D19500099D91 /* dsc_iterator.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */,
F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */,
+ F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
target = F9F2A5580F7AEE9800B7C9EB /* libdsc */;
targetProxy = F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */;
};
+ F9D1004714D8D91100099D91 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F9D1001114D8D0BA00099D91 /* dsc_extractor */;
+ targetProxy = F9D1004614D8D91100099D91 /* PBXContainerItemProxy */;
+ };
F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F9ED4C970630A76000DF4E74 /* dyld */;
buildSettings = {
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
INSTALLHDRS_COPY_PHASE = YES;
PRODUCT_NAME = libdyld;
ZERO_LINK = NO;
F93937350A94FB2900070A07 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
- GCC_DYNAMIC_NO_PIC = YES;
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_THREADSAFE_STATICS = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- PREBINDING = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
PRODUCT_NAME = update_dyld_shared_cache;
VALID_ARCHS = "x86_64 i386";
};
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = x86_64;
+ CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = s;
GCC_THREADSAFE_STATICS = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/$(LOCAL)/bin";
LOCAL = "$(LOCAL_$(RC_TARGET_CONFIG))";
LOCAL_iPhone = local;
- PREBINDING = NO;
PRODUCT_NAME = update_dyld_shared_cache;
STRIP_INSTALLED_PRODUCT = YES;
STRIP_STYLE = debugging;
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
- PREBINDING = NO;
PRODUCT_NAME = dyld_shared_cache_util;
};
name = Debug;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
- PREBINDING = NO;
PRODUCT_NAME = dyld_shared_cache_util;
SKIP_INSTALL = NO;
};
name = Release;
};
- F9B0912411F11D1700096D49 /* Debug */ = {
+ F9D1001314D8D0BB00099D91 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
+ DYLIB_COMPATIBILITY_VERSION = "";
+ DYLIB_CURRENT_VERSION = "";
+ EXECUTABLE_EXTENSION = bundle;
GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
- GCC_MODEL_TUNING = G5;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 0;
- INSTALL_PATH = /usr/local/lib;
- PREBINDING = NO;
- PRODUCT_NAME = libdsc_slider;
+ INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+ MACH_O_TYPE = mh_bundle;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+ PRODUCT_NAME = dsc_extractor;
};
name = Debug;
};
- F9B0912511F11D1700096D49 /* Release */ = {
+ F9D1001414D8D0BB00099D91 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- COPY_PHASE_STRIP = NO;
+ COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- INSTALLHDRS_COPY_PHASE = YES;
- INSTALL_PATH = /usr/local/lib;
- PRODUCT_NAME = dsc_slider;
+ DYLIB_COMPATIBILITY_VERSION = "";
+ DYLIB_CURRENT_VERSION = "";
+ EXECUTABLE_EXTENSION = bundle;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+ MACH_O_TYPE = mh_bundle;
+ OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+ PRODUCT_NAME = dsc_extractor;
ZERO_LINK = NO;
};
name = Release;
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = (
- i386,
- x86_64,
- );
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
BASE_ADDRESS_armv4t = 0x2fe00000;
BASE_ADDRESS_armv5 = 0x2fe00000;
BASE_ADDRESS_armv6 = 0x2fe00000;
BASE_ADDRESS_armv7 = 0x2fe00000;
+ BASE_ADDRESS_armv7f = 0x2fe00000;
+ BASE_ADDRESS_armv7k = 0x2fe00000;
BASE_ADDRESS_i386 = 0x8fe00000;
BASE_ADDRESS_ppc = 0x8fe00000;
BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+ CLANG_CXX_LIBRARY = "libc++";
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
"$(BASE_ADDRESS_$(CURRENT_ARCH))",
"@$(DERIVED_SOURCES_DIR)/archives.txt",
"-nostdlib",
- "-lgcc",
"-Wl,-e,__dyld_start",
"-Wl,-dylinker",
"-Wl,-dylinker_install_name,/usr/lib/dyld",
);
- PREBINDING = NO;
PRODUCT_NAME = dyld;
STRIPFLAGS = "-S";
UNSTRIPPED_PRODUCT = NO;
F9D8C7E0087B087300E93EFB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ARCHS = (
- x86_64,
- i386,
- );
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
BASE_ADDRESS_armv4t = 0x2fe00000;
BASE_ADDRESS_armv5 = 0x2fe00000;
BASE_ADDRESS_armv6 = 0x2fe00000;
BASE_ADDRESS_armv7 = 0x2fe00000;
+ BASE_ADDRESS_armv7f = 0x2fe00000;
+ BASE_ADDRESS_armv7k = 0x2fe00000;
BASE_ADDRESS_i386 = 0x8fe00000;
BASE_ADDRESS_ppc = 0x8fe00000;
BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+ CLANG_CXX_LIBRARY = "libc++";
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
"$(BASE_ADDRESS_$(CURRENT_ARCH))",
"@$(DERIVED_SOURCES_DIR)/archives.txt",
"-nostdlib",
- "-lgcc",
"-Wl,-e,__dyld_start",
"-Wl,-dylinker",
"-Wl,-dylinker_install_name,/usr/lib/dyld",
);
- PREBINDING = NO;
PRODUCT_NAME = dyld;
STRIPFLAGS = "-S";
UNSTRIPPED_PRODUCT = NO;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = /usr/lib/system;
- PREBINDING = NO;
PRODUCT_NAME = dyld;
WARNING_CFLAGS = (
"-Wmost",
INSTALL_PATH = /usr/lib/system;
OTHER_LDFLAGS = (
"-nodefaultlibs",
- "-lSystem",
+ "-Wl,-upward-lSystem",
"-umbrella",
System,
);
- PREBINDING = NO;
PRODUCT_NAME = dyld;
SEPARATE_STRIP = YES;
STRIP_INSTALLED_PRODUCT = YES;
F9D8C7EA087B087300E93EFB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_CXX_LIBRARY = "compiler-default";
};
name = Debug;
};
F9D8C7EC087B087300E93EFB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_CXX_LIBRARY = "compiler-default";
};
name = Release;
};
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
INSTALL_PATH = /usr/local/lib;
- PREBINDING = NO;
PRODUCT_NAME = dsc;
};
name = Debug;
COPY_PHASE_STRIP = NO;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_MODEL_TUNING = G5;
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */ = {
+ F9D1001714D8D0F100099D91 /* Build configuration list for PBXNativeTarget "dsc_extractor" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- F9B0912411F11D1700096D49 /* Debug */,
- F9B0912511F11D1700096D49 /* Release */,
+ F9D1001314D8D0BB00099D91 /* Debug */,
+ F9D1001414D8D0BB00099D91 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
/*
* 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
+
+//
+// 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
--- /dev/null
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+Portions derived from:
+
+--------------------------------------------------------------------
+lookup8.c, by Bob Jenkins, January 4 1997, Public Domain.
+hash(), hash2(), hash3, and mix() are externally useful functions.
+Routines to test the hash are included if SELF_TEST is defined.
+You can use this free for any purpose. It has no warranty.
+--------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+perfect.c: code to generate code for a hash for perfect hashing.
+(c) Bob Jenkins, September 1996, December 1999
+You may use this code in any way you wish, and it is free. No warranty.
+I hereby place this in the public domain.
+Source is http://burtleburtle.net/bob/c/perfect.c
+------------------------------------------------------------------------------
+*/
+
+/*
+ * objc-selopt.h
+ * Interface between libobjc and dyld
+ * for selector uniquing in the dyld shared cache.
+ *
+ * When building the shared cache, dyld locates all selectors and selector
+ * references in the cached images. It builds a perfect hash table out of
+ * them and writes the table into the shared cache copy of libobjc.
+ * libobjc then uses that table as the builtin selector list.
+ *
+ * Versioning
+ * The table has a version number. dyld and objc can both ignore the table
+ * if the other used the wrong version number.
+ *
+ * Completeness
+ * Not all libraries are in the shared cache. Libraries that are in the
+ * shared cache and were optimized are specially marked. Libraries on
+ * disk never include those marks.
+ *
+ * Coherency
+ * Libraries optimized in the shared cache can be replaced by unoptimized
+ * copies from disk when loaded. The copy from disk is not marked and will
+ * be fixed up by libobjc. The shared cache copy is still mapped into the
+ * process, so the table can point to cstring data in that library's part
+ * of the shared cache without trouble.
+ *
+ * Atomicity
+ * dyld writes the table itself last. If dyld marks some metadata as
+ * updated but then fails to write a table for some reason, libobjc
+ * fixes up all metadata as if it were not marked.
+ */
+
+#ifndef _OBJC_SELOPT_H
+#define _OBJC_SELOPT_H
+
+/*
+ DO NOT INCLUDE ANY objc HEADERS HERE
+ dyld USES THIS FILE AND CANNOT SEE THEM
+*/
+#include <stdint.h>
+#include <stdlib.h>
+#ifdef SELOPT_WRITE
+#include <ext/hash_map>
+#endif
+/*
+ DO NOT INCLUDE ANY objc HEADERS HERE
+ dyld USES THIS FILE AND CANNOT SEE THEM
+*/
+
+#ifndef STATIC_ASSERT
+# define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
+# define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
+# define _STATIC_ASSERT3(x, line) \
+ typedef struct { \
+ int _static_assert[(x) ? 0 : -1]; \
+ } _static_assert_ ## line __attribute__((unavailable))
+#endif
+
+#define SELOPT_DEBUG 0
+
+#define S32(x) x = little_endian ? OSSwapHostToLittleInt32(x) : OSSwapHostToBigInt32(x)
+#define S64(x) x = little_endian ? OSSwapHostToLittleInt64(x) : OSSwapHostToBigInt64(x)
+
+namespace objc_opt {
+
+typedef int32_t objc_stringhash_offset_t;
+typedef uint8_t objc_stringhash_check_t;
+
+#ifdef SELOPT_WRITE
+
+// Perfect hash code is at the end of this file.
+
+struct perfect_hash {
+ uint32_t capacity;
+ uint32_t occupied;
+ uint32_t shift;
+ uint32_t mask;
+ uint64_t salt;
+
+ uint32_t scramble[256];
+ uint8_t *tab; // count == mask+1; free with delete[]
+
+ perfect_hash() : tab(0) { }
+
+ ~perfect_hash() { if (tab) delete[] tab; }
+};
+
+struct eqstr {
+ bool operator()(const char* s1, const char* s2) const {
+ return strcmp(s1, s2) == 0;
+ }
+};
+
+// cstring => cstring's vmaddress
+// (used for selector names and class names)
+typedef __gnu_cxx::hash_map<const char *, uint64_t, __gnu_cxx::hash<const char *>, eqstr> string_map;
+
+// class name => (class vmaddress, header_info vmaddress)
+typedef __gnu_cxx::hash_multimap<const char *, std::pair<uint64_t, uint64_t>, __gnu_cxx::hash<const char *>, eqstr> class_map;
+
+static perfect_hash make_perfect(const string_map& strings);
+
+#endif
+
+static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level);
+
+// Precomputed perfect hash table of strings.
+// Base class for precomputed selector table and class table.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_stringhash_t {
+ uint32_t capacity;
+ uint32_t occupied;
+ uint32_t shift;
+ uint32_t mask;
+ uint32_t zero;
+ uint32_t unused; // alignment pad
+ uint64_t salt;
+
+ uint32_t scramble[256];
+ uint8_t tab[0]; /* tab[mask+1] (always power-of-2) */
+ // uint8_t checkbytes[capacity]; /* check byte for each string */
+ // int32_t offsets[capacity]; /* offsets from &capacity to cstrings */
+
+ objc_stringhash_check_t *checkbytes() { return (objc_stringhash_check_t *)&tab[mask+1]; }
+ const objc_stringhash_check_t *checkbytes() const { return (const objc_stringhash_check_t *)&tab[mask+1]; }
+
+ objc_stringhash_offset_t *offsets() { return (objc_stringhash_offset_t *)&checkbytes()[capacity]; }
+ const objc_stringhash_offset_t *offsets() const { return (const objc_stringhash_offset_t *)&checkbytes()[capacity]; }
+
+ uint32_t hash(const char *key) const
+ {
+ uint64_t val = lookup8((uint8_t*)key, strlen(key), salt);
+ uint32_t index = (uint32_t)(val>>shift) ^ scramble[tab[val&mask]];
+ return index;
+ }
+
+ // The check bytes areused to reject strings that aren't in the table
+ // without paging in the table's cstring data. This checkbyte calculation
+ // catches 4785/4815 rejects when launching Safari; a perfect checkbyte
+ // would catch 4796/4815.
+ objc_stringhash_check_t checkbyte(const char *key) const
+ {
+ return
+ ((key[0] & 0x7) << 5)
+ |
+ (strlen(key) & 0x1f);
+ }
+
+#define INDEX_NOT_FOUND (~(uint32_t)0)
+
+ uint32_t getIndex(const char *key) const
+ {
+ uint32_t h = hash(key);
+
+ // Use check byte to reject without paging in the table's cstrings
+ objc_stringhash_check_t h_check = checkbytes()[h];
+ objc_stringhash_check_t key_check = checkbyte(key);
+ bool check_fail = (h_check != key_check);
+#if ! SELOPT_DEBUG
+ if (check_fail) return INDEX_NOT_FOUND;
+#endif
+
+ const char *result = (const char *)this + offsets()[h];
+ if (0 != strcmp(key, result)) return INDEX_NOT_FOUND;
+
+#if SELOPT_DEBUG
+ if (check_fail) abort();
+#endif
+
+ return h;
+ }
+
+#ifdef SELOPT_WRITE
+
+ size_t size()
+ {
+ return sizeof(objc_stringhash_t)
+ + mask+1
+ + capacity * sizeof(objc_stringhash_check_t)
+ + capacity * sizeof(objc_stringhash_offset_t);
+ }
+
+ void byteswap(bool little_endian)
+ {
+ // tab and checkbytes are arrays of bytes, no swap needed
+ for (uint32_t i = 0; i < 256; i++) {
+ S32(scramble[i]);
+ }
+ objc_stringhash_offset_t *o = offsets();
+ for (uint32_t i = 0; i < capacity; i++) {
+ S32(o[i]);
+ }
+
+ S32(capacity);
+ S32(occupied);
+ S32(shift);
+ S32(mask);
+ S32(zero);
+ S64(salt);
+ }
+
+ const char *write(uint64_t base, size_t remaining, string_map& strings)
+ {
+ if (sizeof(objc_stringhash_t) > remaining) {
+ return "selector section too small (metadata not optimized)";
+ }
+
+ if (strings.size() == 0) {
+ bzero(this, sizeof(objc_stringhash_t));
+ return NULL;
+ }
+
+ perfect_hash phash = make_perfect(strings);
+ if (phash.capacity == 0) {
+ return "perfect hash failed (metadata not optimized)";
+ }
+
+ // Set header
+ capacity = phash.capacity;
+ occupied = phash.occupied;
+ shift = phash.shift;
+ mask = phash.mask;
+ zero = 0;
+ unused = 0;
+ salt = phash.salt;
+
+ if (size() > remaining) {
+ return "selector section too small (metadata not optimized)";
+ }
+
+ // Set hash data
+ for (uint32_t i = 0; i < 256; i++) {
+ scramble[i] = phash.scramble[i];
+ }
+ for (uint32_t i = 0; i < phash.mask+1; i++) {
+ tab[i] = phash.tab[i];
+ }
+
+ // Set offsets to ""
+ for (uint32_t i = 0; i < phash.capacity; i++) {
+ offsets()[i] =
+ (objc_stringhash_offset_t)offsetof(objc_stringhash_t, zero);
+ }
+ // Set checkbytes to 0
+ for (uint32_t i = 0; i < phash.capacity; i++) {
+ checkbytes()[i] = 0;
+ }
+
+ // Set real string offsets and checkbytes
+# define SHIFT (64 - 8*sizeof(objc_stringhash_offset_t))
+ string_map::const_iterator s;
+ for (s = strings.begin(); s != strings.end(); ++s) {
+ int64_t offset = s->second - base;
+ if ((offset<<SHIFT)>>SHIFT != offset) {
+ return "selector offset too big (metadata not optimized)";
+ }
+
+ uint32_t h = hash(s->first);
+ offsets()[h] = (objc_stringhash_offset_t)offset;
+ checkbytes()[h] = checkbyte(s->first);
+ }
+# undef SHIFT
+
+ return NULL;
+ }
+
+// SELOPT_WRITE
+#endif
+};
+
+
+// Precomputed selector table.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_selopt_t : objc_stringhash_t {
+ const char *get(const char *key) const
+ {
+ uint32_t h = getIndex(key);
+ if (h == INDEX_NOT_FOUND) return NULL;
+
+ return (const char *)this + offsets()[h];
+ }
+};
+
+// Precomputed class list.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change these structures.
+
+struct objc_classheader_t {
+ objc_stringhash_offset_t clsOffset;
+ objc_stringhash_offset_t hiOffset;
+
+ // For duplicate class names:
+ // clsOffset = count<<1 | 1
+ // duplicated classes are duplicateOffsets[hiOffset..hiOffset+count-1]
+ bool isDuplicate() const { return clsOffset & 1; }
+ uint32_t duplicateCount() const { return clsOffset >> 1; }
+ uint32_t duplicateIndex() const { return hiOffset; }
+};
+
+
+struct objc_clsopt_t : objc_stringhash_t {
+ // ...objc_stringhash_t fields...
+ // objc_classheader_t classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
+ // uint32_t duplicateCount;
+ // objc_classheader_t duplicateOffsets[duplicatedClasses];
+
+ objc_classheader_t *classOffsets() { return (objc_classheader_t *)&offsets()[capacity]; }
+ const objc_classheader_t *classOffsets() const { return (const objc_classheader_t *)&offsets()[capacity]; }
+
+ uint32_t& duplicateCount() { return *(uint32_t *)&classOffsets()[capacity]; }
+ const uint32_t& duplicateCount() const { return *(const uint32_t *)&classOffsets()[capacity]; }
+
+ objc_classheader_t *duplicateOffsets() { return (objc_classheader_t *)(&duplicateCount()+1); }
+ const objc_classheader_t *duplicateOffsets() const { return (const objc_classheader_t *)(&duplicateCount()+1); }
+
+ // 0/NULL/NULL: not found
+ // 1/ptr/ptr: found exactly one
+ // n/NULL/NULL: found N - use getClassesAndHeaders() instead
+ uint32_t getClassAndHeader(const char *key, void*& cls, void*& hi) const
+ {
+ uint32_t h = getIndex(key);
+ if (h == INDEX_NOT_FOUND) {
+ cls = NULL;
+ hi = NULL;
+ return 0;
+ }
+
+ const objc_classheader_t& clshi = classOffsets()[h];
+ if (! clshi.isDuplicate()) {
+ // class appears in exactly one header
+ cls = (void *)((const char *)this + clshi.clsOffset);
+ hi = (void *)((const char *)this + clshi.hiOffset);
+ return 1;
+ }
+ else {
+ // class appears in more than one header - use getClassesAndHeaders
+ cls = NULL;
+ hi = NULL;
+ return clshi.duplicateCount();
+ }
+ }
+
+ void getClassesAndHeaders(const char *key, void **cls, void **hi) const
+ {
+ uint32_t h = getIndex(key);
+ if (h == INDEX_NOT_FOUND) return;
+
+ const objc_classheader_t& clshi = classOffsets()[h];
+ if (! clshi.isDuplicate()) {
+ // class appears in exactly one header
+ cls[0] = (void *)((const char *)this + clshi.clsOffset);
+ hi[0] = (void *)((const char *)this + clshi.hiOffset);
+ }
+ else {
+ // class appears in more than one header
+ uint32_t count = clshi.duplicateCount();
+ const objc_classheader_t *list =
+ &duplicateOffsets()[clshi.duplicateIndex()];
+ for (uint32_t i = 0; i < count; i++) {
+ cls[i] = (void *)((const char *)this + list[i].clsOffset);
+ hi[i] = (void *)((const char *)this + list[i].hiOffset);
+ }
+ }
+ }
+
+#ifdef SELOPT_WRITE
+
+ size_t size()
+ {
+ return
+ objc_stringhash_t::size()
+ + capacity * sizeof(objc_classheader_t)
+ + sizeof(duplicateCount())
+ + duplicateCount() * sizeof(objc_classheader_t);
+ }
+
+ void byteswap(bool little_endian)
+ {
+ objc_classheader_t *o;
+
+ o = classOffsets();
+ for (uint32_t i = 0; i < capacity; i++) {
+ S32(o[i].clsOffset);
+ S32(o[i].hiOffset);
+ }
+
+ o = duplicateOffsets();
+ for (uint32_t i = 0; i < duplicateCount(); i++) {
+ S32(o[i].clsOffset);
+ S32(o[i].hiOffset);
+ }
+
+ S32(duplicateCount());
+
+ objc_stringhash_t::byteswap(little_endian);
+ }
+
+ const char *write(uint64_t base, size_t remaining,
+ string_map& strings, class_map& classes, bool verbose)
+ {
+ const char *err;
+ err = objc_stringhash_t::write(base, remaining, strings);
+ if (err) return err;
+
+ if (size() > remaining) {
+ return "selector section too small (metadata not optimized)";
+ }
+
+ // Set class offsets to &zero
+ objc_stringhash_offset_t zeroOffset =
+ (objc_stringhash_offset_t)offsetof(objc_stringhash_t, zero);
+ for (uint32_t i = 0; i < capacity; i++) {
+ classOffsets()[i].clsOffset = zeroOffset;
+ classOffsets()[i].hiOffset = zeroOffset;
+ }
+
+ // Set real class offsets
+# define SHIFT (64 - 8*sizeof(objc_stringhash_offset_t))
+ class_map::const_iterator c;
+ for (c = classes.begin(); c != classes.end(); ++c) {
+ uint32_t h = getIndex(c->first);
+ if (h == INDEX_NOT_FOUND) {
+ return "class list busted (metadata not optimized)";
+ }
+
+ if (classOffsets()[h].clsOffset != zeroOffset) {
+ // already did this class
+ continue;
+ }
+
+ uint32_t count = classes.count(c->first);
+ if (count == 1) {
+ // only one class with this name
+
+ int64_t coff = c->second.first - base;
+ int64_t hoff = c->second.second - base;
+ if ((coff<<SHIFT)>>SHIFT != coff) {
+ return "class offset too big (metadata not optimized)";
+ }
+ if ((hoff<<SHIFT)>>SHIFT != hoff) {
+ return "header offset too big (metadata not optimized)";
+ }
+
+ classOffsets()[h].clsOffset = (objc_stringhash_offset_t)coff;
+ classOffsets()[h].hiOffset = (objc_stringhash_offset_t)hoff;
+ }
+ else {
+ // class name has duplicates - write them all now
+ if (verbose) {
+ fprintf(stderr, "update_dyld_shared_cache: %u duplicates of Objective-C class %s\n", count, c->first);
+ }
+
+ uint32_t dest = duplicateCount();
+ duplicateCount() += count;
+ if (size() > remaining) {
+ return "selector section too small (metadata not optimized)";
+ }
+
+ // classOffsets() instead contains count and array index
+ classOffsets()[h].clsOffset = count*2 + 1;
+ classOffsets()[h].hiOffset = dest;
+
+ std::pair<class_map::const_iterator, class_map::const_iterator>
+ duplicates = classes.equal_range(c->first);
+ class_map::const_iterator dup;
+ for (dup = duplicates.first; dup != duplicates.second; ++dup) {
+ int64_t coff = dup->second.first - base;
+ int64_t hoff = dup->second.second - base;
+ if ((coff<<SHIFT)>>SHIFT != coff) {
+ return "class offset too big (metadata not optimized)";
+ }
+ if ((hoff<<SHIFT)>>SHIFT != hoff) {
+ return "header offset too big (metadata not optimized)";
+ }
+
+ duplicateOffsets()[dest].clsOffset = (objc_stringhash_offset_t)coff;
+ duplicateOffsets()[dest].hiOffset = (objc_stringhash_offset_t)hoff;
+ dest++;
+ }
+ }
+ }
+# undef SHIFT
+
+ return NULL;
+ }
+
+// SELOPT_WRITE
+#endif
+};
+
+// Precomputed image list.
+struct objc_headeropt_t;
+
+// Precomputed class list.
+struct objc_clsopt_t;
+
+// Edit objc-sel-table.s if you change this value.
+enum { VERSION = 12 };
+
+// Top-level optimization structure.
+// Edit objc-sel-table.s and OPT_INITIALIZER if you change this structure.
+struct objc_opt_t {
+ uint32_t version;
+ int32_t selopt_offset;
+ int32_t headeropt_offset;
+ int32_t clsopt_offset;
+
+ const objc_selopt_t* selopt() const {
+ if (selopt_offset == 0) return NULL;
+ return (objc_selopt_t *)((uint8_t *)this + selopt_offset);
+ }
+ objc_selopt_t* selopt() {
+ if (selopt_offset == 0) return NULL;
+ return (objc_selopt_t *)((uint8_t *)this + selopt_offset);
+ }
+
+ struct objc_headeropt_t* headeropt() const {
+ if (headeropt_offset == 0) return NULL;
+ return (struct objc_headeropt_t *)((uint8_t *)this + headeropt_offset);
+ }
+
+ struct objc_clsopt_t* clsopt() const {
+ if (clsopt_offset == 0) return NULL;
+ return (objc_clsopt_t *)((uint8_t *)this + clsopt_offset);
+ }
+};
+
+// sizeof(objc_opt_t) must be pointer-aligned
+STATIC_ASSERT(sizeof(objc_opt_t) % sizeof(void*) == 0);
+
+// Initializer for empty opt of type uint32_t[].
+#define X8(x) x, x, x, x, x, x, x, x
+#define X64(x) X8(x), X8(x), X8(x), X8(x), X8(x), X8(x), X8(x), X8(x)
+#define X256(x) X64(x), X64(x), X64(x), X64(x)
+#define OPT_INITIALIZER { \
+ /* objc_opt_t */ \
+ objc_opt::VERSION, 16, 0, 0, \
+ /* objc_selopt_t */ \
+ 4, 4, 63, 3, 0, 0, 0,0, X256(0), 0, 0, 16, 16, 16, 16 \
+ /* no objc_headeropt_t */ \
+ /* no objc_clsopt_t */ \
+}
+
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 64-bit values reversibly.
+mix() takes 48 machine instructions, but only 24 cycles on a superscalar
+ machine (like Intel's new MMX architecture). It requires 4 64-bit
+ registers for 4::2 parallelism.
+All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of
+ (a,b,c), and all deltas of bottom bits were tested. All deltas were
+ tested both on random keys and on keys that were nearly all zero.
+ These deltas all cause every bit of c to change between 1/3 and 2/3
+ of the time (well, only 113/400 to 287/400 of the time for some
+ 2-bit delta). These deltas all cause at least 80 bits to change
+ among (a,b,c) when the mix is run either forward or backward (yes it
+ is reversible).
+This implies that a hash using mix64 has no funnels. There may be
+ characteristics with 3-bit deltas or bigger, I didn't test for
+ those.
+--------------------------------------------------------------------
+*/
+#define mix64(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>43); \
+ b -= c; b -= a; b ^= (a<<9); \
+ c -= a; c -= b; c ^= (b>>8); \
+ a -= b; a -= c; a ^= (c>>38); \
+ b -= c; b -= a; b ^= (a<<23); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>35); \
+ b -= c; b -= a; b ^= (a<<49); \
+ c -= a; c -= b; c ^= (b>>11); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<18); \
+ c -= a; c -= b; c ^= (b>>22); \
+}
+
+/*
+--------------------------------------------------------------------
+hash() -- hash a variable-length key into a 64-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ len : the length of the key, counting by bytes
+ level : can be any 8-byte value
+Returns a 64-bit value. Every bit of the key affects every bit of
+the return value. No funnels. Every 1-bit and 2-bit delta achieves
+avalanche. About 41+5len instructions.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 64 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
+
+By Bob Jenkins, Jan 4 1997. bob_jenkins@burtleburtle.net. You may
+use this code any way you wish, private, educational, or commercial,
+but I would appreciate if you give me credit.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^^64
+is acceptable. Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level)
+// uint8_t *k; /* the key */
+// uint64_t length; /* the length of the key */
+// uint64_t level; /* the previous hash, or an arbitrary value */
+{
+ uint64_t a,b,c;
+ size_t len;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = level; /* the previous hash value */
+ c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 24)
+ {
+ a += (k[0] +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24)
+ +((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56));
+ b += (k[8] +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24)
+ +((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56));
+ c += (k[16] +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24)
+ +((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56));
+ mix64(a,b,c);
+ k += 24; len -= 24;
+ }
+
+ /*------------------------------------- handle the last 23 bytes */
+ c += length;
+ switch(len) /* all the case statements fall through */
+ {
+ case 23: c+=((uint64_t)k[22]<<56);
+ case 22: c+=((uint64_t)k[21]<<48);
+ case 21: c+=((uint64_t)k[20]<<40);
+ case 20: c+=((uint64_t)k[19]<<32);
+ case 19: c+=((uint64_t)k[18]<<24);
+ case 18: c+=((uint64_t)k[17]<<16);
+ case 17: c+=((uint64_t)k[16]<<8);
+ /* the first byte of c is reserved for the length */
+ case 16: b+=((uint64_t)k[15]<<56);
+ case 15: b+=((uint64_t)k[14]<<48);
+ case 14: b+=((uint64_t)k[13]<<40);
+ case 13: b+=((uint64_t)k[12]<<32);
+ case 12: b+=((uint64_t)k[11]<<24);
+ case 11: b+=((uint64_t)k[10]<<16);
+ case 10: b+=((uint64_t)k[ 9]<<8);
+ case 9: b+=((uint64_t)k[ 8]);
+ case 8: a+=((uint64_t)k[ 7]<<56);
+ case 7: a+=((uint64_t)k[ 6]<<48);
+ case 6: a+=((uint64_t)k[ 5]<<40);
+ case 5: a+=((uint64_t)k[ 4]<<32);
+ case 4: a+=((uint64_t)k[ 3]<<24);
+ case 3: a+=((uint64_t)k[ 2]<<16);
+ case 2: a+=((uint64_t)k[ 1]<<8);
+ case 1: a+=((uint64_t)k[ 0]);
+ /* case 0: nothing left to add */
+ }
+ mix64(a,b,c);
+ /*-------------------------------------------- report the result */
+ return c;
+}
+
+
+#ifdef SELOPT_WRITE
+
+/*
+------------------------------------------------------------------------------
+This generates a minimal perfect hash function. That means, given a
+set of n keys, this determines a hash function that maps each of
+those keys into a value in 0..n-1 with no collisions.
+
+The perfect hash function first uses a normal hash function on the key
+to determine (a,b) such that the pair (a,b) is distinct for all
+keys, then it computes a^scramble[tab[b]] to get the final perfect hash.
+tab[] is an array of 1-byte values and scramble[] is a 256-term array of
+2-byte or 4-byte values. If there are n keys, the length of tab[] is a
+power of two between n/3 and n.
+
+I found the idea of computing distinct (a,b) values in "Practical minimal
+perfect hash functions for large databases", Fox, Heath, Chen, and Daoud,
+Communications of the ACM, January 1992. They found the idea in Chichelli
+(CACM Jan 1980). Beyond that, our methods differ.
+
+The key is hashed to a pair (a,b) where a in 0..*alen*-1 and b in
+0..*blen*-1. A fast hash function determines both a and b
+simultaneously. Any decent hash function is likely to produce
+hashes so that (a,b) is distinct for all pairs. I try the hash
+using different values of *salt* until all pairs are distinct.
+
+The final hash is (a XOR scramble[tab[b]]). *scramble* is a
+predetermined mapping of 0..255 into 0..smax-1. *tab* is an
+array that we fill in in such a way as to make the hash perfect.
+
+First we fill in all values of *tab* that are used by more than one
+key. We try all possible values for each position until one works.
+
+This leaves m unmapped keys and m values that something could hash to.
+If you treat unmapped keys as lefthand nodes and unused hash values
+as righthand nodes, and draw a line connecting each key to each hash
+value it could map to, you get a bipartite graph. We attempt to
+find a perfect matching in this graph. If we succeed, we have
+determined a perfect hash for the whole set of keys.
+
+*scramble* is used because (a^tab[i]) clusters keys around *a*.
+------------------------------------------------------------------------------
+*/
+
+typedef uint64_t ub8;
+#define UB8MAXVAL 0xffffffffffffffffLL
+#define UB8BITS 64
+typedef uint32_t ub4;
+#define UB4MAXVAL 0xffffffff
+#define UB4BITS 32
+typedef uint16_t ub2;
+#define UB2MAXVAL 0xffff
+#define UB2BITS 16
+typedef uint8_t ub1;
+#define UB1MAXVAL 0xff
+#define UB1BITS 8
+
+#define TRUE 1
+#define FALSE 0
+
+#define SCRAMBLE_LEN 256 // ((ub4)1<<16) /* length of *scramble* */
+#define RETRY_INITKEY 2048 /* number of times to try to find distinct (a,b) */
+#define RETRY_PERFECT 4 /* number of times to try to make a perfect hash */
+
+
+/* representation of a key */
+struct key
+{
+ ub1 *name_k; /* the actual key */
+ ub4 len_k; /* the length of the actual key */
+ ub4 hash_k; /* the initial hash value for this key */
+/* beyond this point is mapping-dependent */
+ ub4 a_k; /* a, of the key maps to (a,b) */
+ ub4 b_k; /* b, of the key maps to (a,b) */
+ struct key *nextb_k; /* next key with this b */
+};
+typedef struct key key;
+
+/* things indexed by b of original (a,b) pair */
+struct bstuff
+{
+ ub2 val_b; /* hash=a^tabb[b].val_b */
+ key *list_b; /* tabb[i].list_b is list of keys with b==i */
+ ub4 listlen_b; /* length of list_b */
+ ub4 water_b; /* high watermark of who has visited this map node */
+};
+typedef struct bstuff bstuff;
+
+/* things indexed by final hash value */
+struct hstuff
+{
+ key *key_h; /* tabh[i].key_h is the key with a hash of i */
+};
+typedef struct hstuff hstuff;
+
+/* things indexed by queue position */
+struct qstuff
+{
+ bstuff *b_q; /* b that currently occupies this hash */
+ ub4 parent_q; /* queue position of parent that could use this hash */
+ ub2 newval_q; /* what to change parent tab[b] to to use this hash */
+ ub2 oldval_q; /* original value of tab[b] */
+};
+typedef struct qstuff qstuff;
+
+
+/*
+------------------------------------------------------------------------------
+Find the mapping that will produce a perfect hash
+------------------------------------------------------------------------------
+*/
+
+/* return the ceiling of the log (base 2) of val */
+static ub4 log2u(ub4 val)
+{
+ ub4 i;
+ for (i=0; ((ub4)1<<i) < val; ++i)
+ ;
+ return i;
+}
+
+/* compute p(x), where p is a permutation of 0..(1<<nbits)-1 */
+/* permute(0)=0. This is intended and useful. */
+static ub4 permute(ub4 x, ub4 nbits)
+// ub4 x; /* input, a value in some range */
+// ub4 nbits; /* input, number of bits in range */
+{
+ int i;
+ int mask = ((ub4)1<<nbits)-1; /* all ones */
+ int const2 = 1+nbits/2;
+ int const3 = 1+nbits/3;
+ int const4 = 1+nbits/4;
+ int const5 = 1+nbits/5;
+ for (i=0; i<20; ++i)
+ {
+ x = (x+(x<<const2)) & mask;
+ x = (x^(x>>const3));
+ x = (x+(x<<const4)) & mask;
+ x = (x^(x>>const5));
+ }
+ return x;
+}
+
+/* initialize scramble[] with distinct random values in 0..smax-1 */
+static void scrambleinit(ub4 *scramble, ub4 smax)
+// ub4 *scramble; /* hash is a^scramble[tab[b]] */
+// ub4 smax; /* scramble values should be in 0..smax-1 */
+{
+ ub4 i;
+
+ /* fill scramble[] with distinct random integers in 0..smax-1 */
+ for (i=0; i<SCRAMBLE_LEN; ++i)
+ {
+ scramble[i] = permute(i, log2u(smax));
+ }
+}
+
+
+/*
+ * put keys in tabb according to key->b_k
+ * check if the initial hash might work
+ */
+static int inittab(bstuff *tabb, ub4 blen, key *keys, ub4 nkeys, int complete)
+// bstuff *tabb; /* output, list of keys with b for (a,b) */
+// ub4 blen; /* length of tabb */
+// key *keys; /* list of keys already hashed */
+// int complete; /* TRUE means to complete init despite collisions */
+{
+ int nocollision = TRUE;
+ ub4 i;
+
+ memset((void *)tabb, 0, (size_t)(sizeof(bstuff)*blen));
+
+ /* Two keys with the same (a,b) guarantees a collision */
+ for (i = 0; i < nkeys; i++) {
+ key *mykey = keys+i;
+ key *otherkey;
+
+ for (otherkey=tabb[mykey->b_k].list_b;
+ otherkey;
+ otherkey=otherkey->nextb_k)
+ {
+ if (mykey->a_k == otherkey->a_k)
+ {
+ nocollision = FALSE;
+ if (!complete)
+ return FALSE;
+ }
+ }
+ ++tabb[mykey->b_k].listlen_b;
+ mykey->nextb_k = tabb[mykey->b_k].list_b;
+ tabb[mykey->b_k].list_b = mykey;
+ }
+
+ /* no two keys have the same (a,b) pair */
+ return nocollision;
+}
+
+
+/* Do the initial hash for normal mode (use lookup and checksum) */
+static void initnorm(key *keys, ub4 nkeys, ub4 alen, ub4 blen, ub4 smax, ub8 salt)
+// key *keys; /* list of all keys */
+// ub4 alen; /* (a,b) has a in 0..alen-1, a power of 2 */
+// ub4 blen; /* (a,b) has b in 0..blen-1, a power of 2 */
+// ub4 smax; /* maximum range of computable hash values */
+// ub4 salt; /* used to initialize the hash function */
+// gencode *final; /* output, code for the final hash */
+{
+ ub4 loga = log2u(alen); /* log based 2 of blen */
+ ub4 i;
+ for (i = 0; i < nkeys; i++) {
+ key *mykey = keys+i;
+ ub8 hash = lookup8(mykey->name_k, mykey->len_k, salt);
+ mykey->a_k = (loga > 0) ? hash>>(UB8BITS-loga) : 0;
+ mykey->b_k = (blen > 1) ? hash&(blen-1) : 0;
+ }
+}
+
+
+/* Try to apply an augmenting list */
+static int apply(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 *scramble, ub4 tail, int rollback)
+// bstuff *tabb;
+// hstuff *tabh;
+// qstuff *tabq;
+// ub4 blen;
+// ub4 *scramble;
+// ub4 tail;
+// int rollback; /* FALSE applies augmenting path, TRUE rolls back */
+{
+ ub4 hash;
+ key *mykey;
+ bstuff *pb;
+ ub4 child;
+ ub4 parent;
+ ub4 stabb; /* scramble[tab[b]] */
+
+ /* walk from child to parent */
+ for (child=tail-1; child; child=parent)
+ {
+ parent = tabq[child].parent_q; /* find child's parent */
+ pb = tabq[parent].b_q; /* find parent's list of siblings */
+
+ /* erase old hash values */
+ stabb = scramble[pb->val_b];
+ for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+ {
+ hash = mykey->a_k^stabb;
+ if (mykey == tabh[hash].key_h)
+ { /* erase hash for all of child's siblings */
+ tabh[hash].key_h = (key *)0;
+ }
+ }
+
+ /* change pb->val_b, which will change the hashes of all parent siblings */
+ pb->val_b = (rollback ? tabq[child].oldval_q : tabq[child].newval_q);
+
+ /* set new hash values */
+ stabb = scramble[pb->val_b];
+ for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+ {
+ hash = mykey->a_k^stabb;
+ if (rollback)
+ {
+ if (parent == 0) continue; /* root never had a hash */
+ }
+ else if (tabh[hash].key_h)
+ {
+ /* very rare: roll back any changes */
+ apply(tabb, tabh, tabq, blen, scramble, tail, TRUE);
+ return FALSE; /* failure, collision */
+ }
+ tabh[hash].key_h = mykey;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+augment(): Add item to the mapping.
+
+Construct a spanning tree of *b*s with *item* as root, where each
+parent can have all its hashes changed (by some new val_b) with
+at most one collision, and each child is the b of that collision.
+
+I got this from Tarjan's "Data Structures and Network Algorithms". The
+path from *item* to a *b* that can be remapped with no collision is
+an "augmenting path". Change values of tab[b] along the path so that
+the unmapped key gets mapped and the unused hash value gets used.
+
+Assuming 1 key per b, if m out of n hash values are still unused,
+you should expect the transitive closure to cover n/m nodes before
+an unused node is found. Sum(i=1..n)(n/i) is about nlogn, so expect
+this approach to take about nlogn time to map all single-key b's.
+-------------------------------------------------------------------------------
+*/
+static int augment(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 *scramble, ub4 smax, bstuff *item, ub4 nkeys,
+ ub4 highwater)
+// bstuff *tabb; /* stuff indexed by b */
+// hstuff *tabh; /* which key is associated with which hash, indexed by hash */
+// qstuff *tabq; /* queue of *b* values, this is the spanning tree */
+// ub4 blen; /* length of tabb */
+// ub4 *scramble; /* final hash is a^scramble[tab[b]] */
+// ub4 smax; /* highest value in scramble */
+// bstuff *item; /* &tabb[b] for the b to be mapped */
+// ub4 nkeys; /* final hash must be in 0..nkeys-1 */
+// ub4 highwater; /* a value higher than any now in tabb[].water_b */
+{
+ ub4 q; /* current position walking through the queue */
+ ub4 tail; /* tail of the queue. 0 is the head of the queue. */
+ ub4 limit=UB1MAXVAL+1;
+ ub4 highhash = smax;
+
+ /* initialize the root of the spanning tree */
+ tabq[0].b_q = item;
+ tail = 1;
+
+ /* construct the spanning tree by walking the queue, add children to tail */
+ for (q=0; q<tail; ++q)
+ {
+ bstuff *myb = tabq[q].b_q; /* the b for this node */
+ ub4 i; /* possible value for myb->val_b */
+
+ if (q == 1)
+ break; /* don't do transitive closure */
+
+ for (i=0; i<limit; ++i)
+ {
+ bstuff *childb = (bstuff *)0; /* the b that this i maps to */
+ key *mykey; /* for walking through myb's keys */
+
+ for (mykey = myb->list_b; mykey; mykey=mykey->nextb_k)
+ {
+ key *childkey;
+ ub4 hash = mykey->a_k^scramble[i];
+
+ if (hash >= highhash) break; /* out of bounds */
+ childkey = tabh[hash].key_h;
+
+ if (childkey)
+ {
+ bstuff *hitb = &tabb[childkey->b_k];
+
+ if (childb)
+ {
+ if (childb != hitb) break; /* hit at most one child b */
+ }
+ else
+ {
+ childb = hitb; /* remember this as childb */
+ if (childb->water_b == highwater) break; /* already explored */
+ }
+ }
+ }
+ if (mykey) continue; /* myb with i has multiple collisions */
+
+ /* add childb to the queue of reachable things */
+ if (childb) childb->water_b = highwater;
+ tabq[tail].b_q = childb;
+ tabq[tail].newval_q = i; /* how to make parent (myb) use this hash */
+ tabq[tail].oldval_q = myb->val_b; /* need this for rollback */
+ tabq[tail].parent_q = q;
+ ++tail;
+
+ if (!childb)
+ { /* found an *i* with no collisions? */
+ /* try to apply the augmenting path */
+ if (apply(tabb, tabh, tabq, blen, scramble, tail, FALSE))
+ return TRUE; /* success, item was added to the perfect hash */
+
+ --tail; /* don't know how to handle such a child! */
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/* find a mapping that makes this a perfect hash */
+static int perfect(bstuff *tabb, hstuff *tabh, qstuff *tabq, ub4 blen, ub4 smax, ub4 *scramble, ub4 nkeys)
+{
+ ub4 maxkeys; /* maximum number of keys for any b */
+ ub4 i, j;
+
+#if SELOPT_DEBUG
+ fprintf(stderr, " blen %d smax %d nkeys %d\n", blen, smax, nkeys);
+#endif
+
+ /* clear any state from previous attempts */
+ memset((void *)tabh, 0, sizeof(hstuff)*smax);
+ memset((void *)tabq, 0, sizeof(qstuff)*(blen+1));
+
+ for (maxkeys=0,i=0; i<blen; ++i)
+ if (tabb[i].listlen_b > maxkeys)
+ maxkeys = tabb[i].listlen_b;
+
+ /* In descending order by number of keys, map all *b*s */
+ for (j=maxkeys; j>0; --j)
+ for (i=0; i<blen; ++i)
+ if (tabb[i].listlen_b == j)
+ if (!augment(tabb, tabh, tabq, blen, scramble, smax, &tabb[i], nkeys,
+ i+1))
+ {
+ return FALSE;
+ }
+
+ /* Success! We found a perfect hash of all keys into 0..nkeys-1. */
+ return TRUE;
+}
+
+
+/* guess initial values for alen and blen */
+static void initalen(ub4 *alen, ub4 *blen, ub4 smax, ub4 nkeys)
+// ub4 *alen; /* output, initial alen */
+// ub4 *blen; /* output, initial blen */
+// ub4 smax; /* input, power of two greater or equal to max hash value */
+// ub4 nkeys; /* number of keys being hashed */
+{
+ /*
+ * Find initial *alen, *blen
+ * Initial alen and blen values were found empirically. Some factors:
+ *
+ * If smax<256 there is no scramble, so tab[b] needs to cover 0..smax-1.
+ *
+ * alen and blen must be powers of 2 because the values in 0..alen-1 and
+ * 0..blen-1 are produced by applying a bitmask to the initial hash function.
+ *
+ * alen must be less than smax, in fact less than nkeys, because otherwise
+ * there would often be no i such that a^scramble[i] is in 0..nkeys-1 for
+ * all the *a*s associated with a given *b*, so there would be no legal
+ * value to assign to tab[b]. This only matters when we're doing a minimal
+ * perfect hash.
+ *
+ * It takes around 800 trials to find distinct (a,b) with nkey=smax*(5/8)
+ * and alen*blen = smax*smax/32.
+ *
+ * Values of blen less than smax/4 never work, and smax/2 always works.
+ *
+ * We want blen as small as possible because it is the number of bytes in
+ * the huge array we must create for the perfect hash.
+ *
+ * When nkey <= smax*(5/8), blen=smax/4 works much more often with
+ * alen=smax/8 than with alen=smax/4. Above smax*(5/8), blen=smax/4
+ * doesn't seem to care whether alen=smax/8 or alen=smax/4. I think it
+ * has something to do with 5/8 = 1/8 * 5. For example examine 80000,
+ * 85000, and 90000 keys with different values of alen. This only matters
+ * if we're doing a minimal perfect hash.
+ *
+ * When alen*blen <= 1<<UB4BITS, the initial hash must produce one integer.
+ * Bigger than that it must produce two integers, which increases the
+ * cost of the hash per character hashed.
+ */
+ *alen = smax; /* no reason to restrict alen to smax/2 */
+ *blen = ((nkeys <= smax*0.6) ? smax/16 :
+ (nkeys <= smax*0.8) ? smax/8 : smax/4);
+
+ if (*alen < 1) *alen = 1;
+ if (*blen < 1) *blen = 1;
+
+#if SELOPT_DEBUG
+ fprintf(stderr, "alen %d blen %d smax %d nkeys %d\n", *alen, *blen, smax, nkeys);
+#endif
+}
+
+/*
+** Try to find a perfect hash function.
+** Return the successful initializer for the initial hash.
+** Return 0 if no perfect hash could be found.
+*/
+static int findhash(bstuff **tabb, ub4 *alen, ub4 *blen, ub8 *salt,
+ ub4 *scramble, ub4 smax, key *keys, ub4 nkeys)
+// bstuff **tabb; /* output, tab[] of the perfect hash, length *blen */
+// ub4 *alen; /* output, 0..alen-1 is range for a of (a,b) */
+// ub4 *blen; /* output, 0..blen-1 is range for b of (a,b) */
+// ub4 *salt; /* output, initializes initial hash */
+// ub4 *scramble; /* input, hash = a^scramble[tab[b]] */
+// ub4 smax; /* input, scramble[i] in 0..smax-1 */
+// key *keys; /* input, keys to hash */
+// ub4 nkeys; /* input, number of keys being hashed */
+{
+ ub4 bad_initkey; /* how many times did initkey fail? */
+ ub4 bad_perfect; /* how many times did perfect fail? */
+ ub4 si; /* trial initializer for initial hash */
+ ub4 maxalen;
+ hstuff *tabh; /* table of keys indexed by hash value */
+ qstuff *tabq; /* table of stuff indexed by queue value, used by augment */
+
+ /* guess initial values for alen and blen */
+ initalen(alen, blen, smax, nkeys);
+
+ scrambleinit(scramble, smax);
+
+ maxalen = smax;
+
+ /* allocate working memory */
+ *tabb = new bstuff[*blen];
+ tabq = new qstuff[*blen+1];
+ tabh = new hstuff[smax];
+
+ /* Actually find the perfect hash */
+ *salt = 0;
+ bad_initkey = 0;
+ bad_perfect = 0;
+ for (si=1; ; ++si)
+ {
+ ub4 rslinit;
+ /* Try to find distinct (A,B) for all keys */
+ *salt = si * 0x9e3779b97f4a7c13LL; /* golden ratio (arbitrary value) */
+ initnorm(keys, nkeys, *alen, *blen, smax, *salt);
+ rslinit = inittab(*tabb, *blen, keys, nkeys, FALSE);
+ if (rslinit == 0)
+ {
+ /* didn't find distinct (a,b) */
+ if (++bad_initkey >= RETRY_INITKEY)
+ {
+ /* Try to put more bits in (A,B) to make distinct (A,B) more likely */
+ if (*alen < maxalen)
+ {
+ *alen *= 2;
+ }
+ else if (*blen < smax)
+ {
+ *blen *= 2;
+ delete[] tabq;
+ delete[] *tabb;
+ *tabb = new bstuff[*blen];
+ tabq = new qstuff[*blen+1];
+ }
+ bad_initkey = 0;
+ bad_perfect = 0;
+ }
+ continue; /* two keys have same (a,b) pair */
+ }
+
+ /* Given distinct (A,B) for all keys, build a perfect hash */
+ if (!perfect(*tabb, tabh, tabq, *blen, smax, scramble, nkeys))
+ {
+ if (++bad_perfect >= RETRY_PERFECT)
+ {
+ if (*blen < smax)
+ {
+ *blen *= 2;
+ delete[] *tabb;
+ delete[] tabq;
+ *tabb = new bstuff[*blen];
+ tabq = new qstuff[*blen+1];
+ --si; /* we know this salt got distinct (A,B) */
+ }
+ else
+ {
+ return 0;
+ }
+ bad_perfect = 0;
+ }
+ continue;
+ }
+
+ break;
+ }
+
+ /* free working memory */
+ delete[] tabh;
+ delete[] tabq;
+
+ return 1;
+}
+
+/*
+------------------------------------------------------------------------------
+Input/output type routines
+------------------------------------------------------------------------------
+*/
+
+/* get the list of keys */
+static void getkeys(key **keys, ub4 *nkeys, const string_map& strings)
+{
+ key *buf = new key[strings.size()];
+ size_t i;
+ string_map::const_iterator s;
+ for (i = 0, s = strings.begin(); s != strings.end(); ++s, ++i) {
+ key *mykey = buf+i;
+ mykey->name_k = (ub1 *)s->first;
+ mykey->len_k = (ub4)strlen(s->first);
+ }
+ *keys = buf;
+ *nkeys = strings.size();
+}
+
+
+static perfect_hash
+make_perfect(const string_map& strings)
+{
+ ub4 nkeys; /* number of keys */
+ key *keys; /* head of list of keys */
+ bstuff *tab; /* table indexed by b */
+ ub4 smax; /* scramble[] values in 0..smax-1, a power of 2 */
+ ub4 alen; /* a in 0..alen-1, a power of 2 */
+ ub4 blen; /* b in 0..blen-1, a power of 2 */
+ ub8 salt; /* a parameter to the hash function */
+ ub4 scramble[SCRAMBLE_LEN]; /* used in final hash function */
+ int ok;
+ int i;
+ perfect_hash result;
+
+ /* read in the list of keywords */
+ getkeys(&keys, &nkeys, strings);
+
+ /* find the hash */
+ smax = ((ub4)1<<log2u(nkeys));
+ ok = findhash(&tab, &alen, &blen, &salt,
+ scramble, smax, keys, nkeys);
+ if (!ok) {
+ smax = 2 * ((ub4)1<<log2u(nkeys));
+ ok = findhash(&tab, &alen, &blen, &salt,
+ scramble, smax, keys, nkeys);
+ }
+ if (!ok) {
+ bzero(&result, sizeof(result));
+ } else {
+ /* build the tables */
+ result.capacity = smax;
+ result.occupied = nkeys;
+ result.shift = UB8BITS - log2u(alen);
+ result.mask = blen - 1;
+ result.salt = salt;
+
+ result.tab = new uint8_t[blen];
+ for (i = 0; i < blen; i++) {
+ result.tab[i] = tab[i].val_b;
+ }
+ for (i = 0; i < 256; i++) {
+ result.scramble[i] = scramble[i];
+ }
+ }
+
+ delete[] keys;
+ delete[] tab;
+
+ return result;
+}
+
+// SELOPT_WRITE
+#endif
+
+// namespace objc_selopt
+};
+
+#undef S32
+#undef S64
+
+#endif
//
// Architectures
//
-struct ppc
-{
- typedef Pointer32<BigEndian> P;
-
-};
-
struct x86
{
typedef Pointer32<LittleEndian> P;
void doBindDyldLazyInfo(std::vector<void*>& pointersInData);
void bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type,
int libraryOrdinal, int64_t addend,
- const char* symbolName, bool lazyPointer,
+ const char* symbolName, bool lazyPointer, bool weakImport,
std::vector<void*>& pointersInData);
pint_t resolveUndefined(const macho_nlist<P>* undefinedSymbol);
bool findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol);
fDyldInfo = (macho_dyld_info_command<P>*)cmd;
break;
case LC_RPATH:
- throwf("LC_RPATH not supported in dylibs in dyld shared cache");
+ throwf("dyld shared cache does not support LC_RPATH found in %s", layout.getFilePath());
break;
default:
if ( cmd->cmd() & LC_REQ_DYLD )
}
}
-template <> uint8_t Binder<ppc>::pointerRelocSize() { return 2; }
template <> uint8_t Binder<x86>::pointerRelocSize() { return 2; }
template <> uint8_t Binder<x86_64>::pointerRelocSize() { return 3; }
template <> uint8_t Binder<arm>::pointerRelocSize() { return 2; }
-template <> uint8_t Binder<ppc>::pointerRelocType() { return GENERIC_RELOC_VANILLA; }
template <> uint8_t Binder<x86>::pointerRelocType() { return GENERIC_RELOC_VANILLA; }
template <> uint8_t Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
template <> uint8_t Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
}
}
}
- 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;
}
template <typename A>
void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal,
- int64_t addend, const char* symbolName, bool lazyPointer, std::vector<void*>& pointersInData)
+ int64_t addend, const char* symbolName, bool lazyPointer, bool weakImport, std::vector<void*>& pointersInData)
{
//printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
pint_t targetSymbolAddress;
bool isResolverSymbol;
Binder<A>* foundIn;
- if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) )
- throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
-
+ if ( weakImport && (binder == NULL) ) {
+ targetSymbolAddress = 0;
+ foundIn = NULL;
+ isResolverSymbol = false;
+ }
+ else {
+ if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) )
+ throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
+ }
+
// don't bind lazy pointers to resolver stubs in shared cache
if ( lazyPointer && isResolverSymbol ) {
if ( foundIn == this ) {
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;
}
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
symbolName = (char*)p;
while (*p != '\0')
++p;
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:
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;
}
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
symbolName = (char*)p;
while (*p != '\0')
++p;
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;
#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 */
#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"
return NULL;
}
+ const macho_load_command<P>* getLoadCommand(int query) const
+ {
+ const macho_load_command<P>* cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
+ uint32_t cmd_count = this->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == query ) {
+ return cmd;
+ }
+ cmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ return NULL;
+ }
+
typedef typename P::E E;
private:
macho_header_content<P> header;
}
try {
switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
- case CPU_TYPE_POWERPC:
- fLayouts.push_back(new MachOLayout<ppc>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
- break;
case CPU_TYPE_I386:
fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
break;
case CPU_TYPE_ARM:
fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
break;
- case CPU_TYPE_POWERPC64:
- // ignore ppc64 slices
- break;
default:
throw "unknown slice in fat file";
}
}
else {
try {
- if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
- if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(mh->cputype), OSSwapBigToHostInt32(mh->cpusubtype)) )
- fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
- }
- else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
}
if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
}
- else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
- // ignore ppc64 slices
- }
else {
throw "unknown file format";
}
}
-template <> cpu_type_t MachOLayout<ppc>::arch() { return CPU_TYPE_POWERPC; }
template <> cpu_type_t MachOLayout<x86>::arch() { return CPU_TYPE_I386; }
template <> cpu_type_t MachOLayout<x86_64>::arch() { return CPU_TYPE_X86_64; }
template <> cpu_type_t MachOLayout<arm>::arch() { return CPU_TYPE_ARM; }
-template <>
-bool MachOLayout<ppc>::isSplitSeg() const
-{
- return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
-}
-
template <>
bool MachOLayout<x86>::isSplitSeg() const
{
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
#include <mach-o/x86_64/reloc.h>
#include <mach-o/arm/reloc.h>
#include <vector>
fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides();
}
-template <> cpu_type_t Rebaser<ppc>::getArchitecture() const { return CPU_TYPE_POWERPC; }
template <> cpu_type_t Rebaser<x86>::getArchitecture() const { return CPU_TYPE_I386; }
template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
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);
}
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:
}
}
-template <>
-void Rebaser<ppc>::doLocalRelocation(const macho_relocation_info<P>* reloc)
-{
- if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
- if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
- pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
- pint_t value = P::getP(*addr);
- P::setP(*addr, value + this->getSlideForVMAddress(value));
- }
- }
- else {
- macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
- if ( sreloc->r_type() == PPC_RELOC_PB_LA_PTR ) {
- sreloc->set_r_value( sreloc->r_value() + this->getSlideForVMAddress(sreloc->r_value()) );
- }
- else {
- throw "cannot rebase final linked image with scattered relocations";
- }
- }
-}
-
template <>
void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
{
uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
try {
switch ( OSSwapBigToHostInt32(archs[i].cputype) ) {
- case CPU_TYPE_POWERPC:
- fRebasers.push_back(new Rebaser<ppc>(&p[fileOffset]));
- break;
case CPU_TYPE_I386:
fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
break;
}
else {
try {
- if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
- fRebasers.push_back(new Rebaser<ppc>(mh));
- }
- else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+ if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
fRebasers.push_back(new Rebaser<x86>(mh));
}
else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
* @APPLE_LICENSE_HEADER_END@
*/
+#define OBJC_IMAGE_SUPPORTS_GC (1<<1)
+#define OBJC_IMAGE_REQUIRES_GC (1<<2)
+
template <typename A>
struct objc_image_info {
uint32_t version;
uint32_t flags;
+ uint32_t getFlags() INLINE { return A::P::E::get32(flags); }
+
+ bool supportsGCFlagSet() INLINE { return getFlags() & OBJC_IMAGE_SUPPORTS_GC; }
+ bool requiresGCFlagSet() INLINE { return getFlags() & OBJC_IMAGE_REQUIRES_GC; }
+
void setFlag(uint32_t bits) INLINE { uint32_t old = A::P::E::get32(flags); A::P::E::set32(flags, old | bits); }
- void setSelectorsPrebound() INLINE { setFlag(1<<3); }
+ void setOptimizedByDyld() INLINE { setFlag(1<<3); }
};
template <typename A>
uint64_t newValue = visitor.visit(oldValue);
selrefs.set(s, newValue);
}
-
- // Mark image_info
- const macho_section<P> *imageInfoSection =
- header->getSection("__OBJC", "__image_info");
- if (imageInfoSection) {
- objc_image_info<A> *info = (objc_image_info<A> *)
- cache->mappedAddressForVMAddress(imageInfoSection->addr());
- info->setSelectorsPrebound();
- }
}
};
* @APPLE_LICENSE_HEADER_END@
*/
+#include "MachOLayout.hpp"
#include <iterator>
#include <deque>
}
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; }
}
}
};
+
+template <typename A>
+class objc_header_info_t {
+
+ typedef typename A::P P;
+ typedef typename A::P::uint_t pint_t;
+
+ pint_t next; // objc_header_info *
+ pint_t mhdr; // mach_header or mach_header_64
+ pint_t info; // objc_image_info *
+ pint_t fname; // const char *
+ bool loaded;
+ bool inSharedCache;
+ bool allClassesRealized;
+
+public:
+ objc_header_info_t(SharedCache<A>* cache, const macho_header<P>* mh)
+ : next(0),
+ mhdr(0),
+ info(0),
+ fname(0),
+ loaded(0),
+ allClassesRealized(0)
+ {
+ A::P::setP(mhdr, cache->VMAddressForMappedAddress(mh));
+ const macho_section<P>* sect = mh->getSection("__DATA", "__objc_imageinfo");
+ if (sect) A::P::setP(info, sect->addr());
+
+ // can't set fname because dyld sometimes edits it
+ }
+
+ void addPointers(std::vector<void*>& pointersToAdd) {
+ pointersToAdd.push_back(&mhdr);
+ if (info) pointersToAdd.push_back(&info);
+ }
+
+ uint64_t header_vmaddr() const { return mhdr; }
+};
template <typename A> class objc_method_list_t; // forward reference
template <typename A>
class objc_ivar_t {
+ typedef typename A::P::uint_t pint_t;
typename A::P::uint_t offset; // A::P *
typename A::P::uint_t name; // const char *
typename A::P::uint_t type; // const char *
uint32_t alignment;
uint32_t size;
+
+public:
+ const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
+
+ bool hasOffset() const { return A::P::getP(offset) != 0; }
+ pint_t getOffset(SharedCache<A> *cache) const { return A::P::getP(*(pint_t * const)cache->mappedAddressForVMAddress(A::P::getP(offset))); }
+ void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::setP(*(pint_t *)cache->mappedAddressForVMAddress(A::P::getP(offset)), newOffset); }
+
+ uint32_t getAlignment()
+ {
+ uint32_t a = A::P::E::get32(alignment);
+ return a == (uint32_t)-1 ? sizeof(typename A::P::uint_t) : 1<<a;
+ }
};
template <typename A>
class objc_ivar_list_t {
+ typedef typename A::P::uint_t pint_t;
uint32_t entsize;
uint32_t count;
objc_ivar_t<A> first;
uint32_t getEntsize() const { return A::P::E::get32(entsize); }
- objc_ivar_t<A>& get(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
+ objc_ivar_t<A>& get(pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
uint32_t byteSize() const {
return byteSizeForCount(getCount(), getEntsize());
typename A::P::uint_t baseProperties;
public:
+ bool isMetaClass() { return A::P::E::get32(flags) & 1; }
+
+ uint32_t getInstanceStart() { return A::P::E::get32(instanceStart); }
+ void setInstanceStart(uint32_t newStart) { A::P::E::set32(instanceStart, newStart); }
+
+ uint32_t getInstanceSize() { return A::P::E::get32(instanceSize.instanceSize); }
+ void setInstanceSize(uint32_t newSiz) { A::P::E::set32(instanceSize.instanceSize, newSiz); }
+
objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
+ objc_ivar_list_t<A> *getIvarList(SharedCache<A>* cache) const { return (objc_ivar_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(ivars)); }
+
objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
typename A::P::uint_t data;
public:
+ bool isMetaClass(SharedCache<A>* cache) const { return getData(cache)->isMetaClass(); }
+
objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
+ objc_class_t<A> *getSuperclass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(superclass)); }
+
objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
};
+// Call visitor.visitIvar() on every ivar in a given class.
+template <typename A, typename V>
+class IvarWalker {
+ typedef typename A::P P;
+ typedef typename A::P::uint_t pint_t;
+ V& ivarVisitor;
+public:
+
+ IvarWalker(V& visitor) : ivarVisitor(visitor) { }
+
+ void walk(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
+ {
+ objc_class_data_t<A> *data = cls->getData(cache);
+ objc_ivar_list_t<A> *ivars = data->getIvarList(cache);
+ if (ivars) {
+ for (pint_t i = 0; i < ivars->getCount(); i++) {
+ objc_ivar_t<A>& ivar = ivars->get(i);
+ //fprintf(stderr, "visiting ivar: %s\n", ivar.getName(cache));
+ ivarVisitor.visitIvar(cache, header, cls, &ivar);
+ }
+ } else {
+ //fprintf(stderr, "no ivars\n");
+ }
+ }
+
+ void visitClass(SharedCache<A>* cache, const macho_header<P>* header, objc_class_t<A> *cls)
+ {
+ walk(cache, header, cls);
+ }
+};
+
+// Call visitor.visitClass() on every class.
+template <typename A, typename V>
+class ClassWalker {
+ typedef typename A::P P;
+ typedef typename A::P::uint_t pint_t;
+ V& classVisitor;
+public:
+
+ ClassWalker(V& visitor) : classVisitor(visitor) { }
+
+ void walk(SharedCache<A>* cache, const macho_header<P>* header)
+ {
+ PointerSection<A, objc_class_t<A> *>
+ classes(cache, header, "__DATA", "__objc_classlist");
+
+ for (pint_t i = 0; i < classes.count(); i++) {
+ objc_class_t<A> *cls = classes.get(i);
+ //fprintf(stderr, "visiting class: %s\n", cls->getName(cache));
+ classVisitor.visitClass(cache, header, cls);
+ }
+ }
+};
+
// Call visitor.visitMethodList(mlist) on every method list in a header.
template <typename A, typename V>
MethodListWalker(V& visitor) : mVisitor(visitor) { }
- void walk(SharedCache<A>* cache, const macho_header<P>* header)
+ void walk(SharedCache<A>* cache, const macho_header<P>* header, bool walkProtocols)
{
// Method lists in classes
PointerSection<A, objc_class_t<A> *>
}
}
- // Method description lists from protocols
- PointerSection<A, objc_protocol_t<A> *>
- protocols(cache, header, "__DATA", "__objc_protolist");
- for (pint_t i = 0; i < protocols.count(); i++) {
- objc_protocol_t<A> *proto = protocols.get(i);
- objc_method_list_t<A> *mlist;
- if ((mlist = proto->getInstanceMethods(cache))) {
- mVisitor.visitMethodList(mlist);
- }
- if ((mlist = proto->getClassMethods(cache))) {
- mVisitor.visitMethodList(mlist);
- }
- if ((mlist = proto->getOptionalInstanceMethods(cache))) {
- mVisitor.visitMethodList(mlist);
- }
- if ((mlist = proto->getOptionalClassMethods(cache))) {
- mVisitor.visitMethodList(mlist);
- }
- }
+ // Method description lists from protocols
+ if ( walkProtocols ) {
+ PointerSection<A, objc_protocol_t<A> *>
+ protocols(cache, header, "__DATA", "__objc_protolist");
+ for (pint_t i = 0; i < protocols.count(); i++) {
+ objc_protocol_t<A> *proto = protocols.get(i);
+ objc_method_list_t<A> *mlist;
+ if ((mlist = proto->getInstanceMethods(cache))) {
+ mVisitor.visitMethodList(mlist);
+ }
+ if ((mlist = proto->getClassMethods(cache))) {
+ mVisitor.visitMethodList(mlist);
+ }
+ if ((mlist = proto->getOptionalInstanceMethods(cache))) {
+ mVisitor.visitMethodList(mlist);
+ }
+ if ((mlist = proto->getOptionalClassMethods(cache))) {
+ mVisitor.visitMethodList(mlist);
+ }
+ }
+ }
}
};
{
// method lists of all kinds
MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
- mw.walk(cache, header);
+ mw.walk(cache, header, true);
// @selector references
PointerSection<A, const char *>
pint_t newValue = mVisitor.visit(oldValue);
msg.setName(newValue);
}
+ }
+};
- // Mark image_info
- const macho_section<P> *imageInfoSection =
- header->getSection("__DATA", "__objc_imageinfo");
+
+// Update selector references. The visitor performs recording and uniquing.
+template <typename A>
+class IvarOffsetOptimizer {
+ typedef typename A::P P;
+
+ uint32_t slide;
+ uint32_t maxAlignment;
+
+ uint32_t fOptimized;
+
+public:
+
+ IvarOffsetOptimizer() : fOptimized(0) { }
+
+ size_t optimized() const { return fOptimized; }
+
+ // dual purpose ivar visitor function
+ // if slide!=0 then slides the ivar by that amount, otherwise computes maxAlignment
+ void visitIvar(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls, objc_ivar_t<A> *ivar)
+ {
+ if (slide == 0) {
+ uint32_t alignment = ivar->getAlignment();
+ if (alignment > maxAlignment) maxAlignment = alignment;
+ } else {
+ // skip anonymous bitfields
+ if (ivar->hasOffset()) {
+ uint32_t oldOffset = (uint32_t)ivar->getOffset(cache);
+ ivar->setOffset(cache, oldOffset + slide);
+ fOptimized++;
+ //fprintf(stderr, "%d -> %d for %s.%s\n", oldOffset, oldOffset + slide, cls->getName(cache), ivar->getName(cache));
+ } else {
+ //fprintf(stderr, "NULL offset\n");
+ }
+ }
+ }
+
+ // Class visitor function. Evaluates whether to slide ivars and performs slide if needed.
+ // The slide algorithm is also implemented in objc. Any changes here should be reflected there also.
+ void visitClass(SharedCache<A>* cache, const macho_header<P>* /*unused, may be NULL*/, objc_class_t<A> *cls)
+ {
+ objc_class_t<A> *super = cls->getSuperclass(cache);
+ if (super) {
+ // Recursively visit superclasses to ensure we have the correct superclass start
+ // Note that we don't need the macho_header, so just pass NULL.
+ visitClass(cache, NULL, super);
+
+ objc_class_data_t<A> *data = cls->getData(cache);
+ objc_class_data_t<A> *super_data = super->getData(cache);
+ int32_t diff = super_data->getInstanceSize() - data->getInstanceStart();
+ if (diff > 0) {
+ IvarWalker<A, IvarOffsetOptimizer<A> > ivarVisitor(*this);
+ maxAlignment = 0;
+ slide = 0;
+
+ // This walk computes maxAlignment
+ ivarVisitor.walk(cache, NULL, cls);
+
+ // Compute a slide value that preserves that alignment
+ uint32_t alignMask = maxAlignment - 1;
+ if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
+
+ // Slide all of this class's ivars en masse
+ slide = diff;
+ if (slide != 0) {
+ //fprintf(stderr, "Sliding ivars in %s by %u (superclass was %d, now %d)\n", cls->getName(cache), slide, data->getInstanceStart(), super_data->getInstanceSize());
+ ivarVisitor.walk(cache, NULL, cls);
+ data->setInstanceStart(data->getInstanceStart() + slide);
+ data->setInstanceSize(data->getInstanceSize() + slide);
+ }
+ }
+ }
+ }
+
+ // Enumerates objc classes in the module and performs any ivar slides
+ void optimize(SharedCache<A>* cache, const macho_header<P>* header)
+ {
+ // The slide code cannot fix up GC layout strings so skip modules that support ore require GC
+ const macho_section<P> *imageInfoSection = header->getSection("__DATA", "__objc_imageinfo");
if (imageInfoSection) {
- objc_image_info<A> *info = (objc_image_info<A> *)
- cache->mappedAddressForVMAddress(imageInfoSection->addr());
- info->setSelectorsPrebound();
+ objc_image_info<A> *info = (objc_image_info<A> *)cache->mappedAddressForVMAddress(imageInfoSection->addr());
+ if (!info->supportsGCFlagSet() && !info->requiresGCFlagSet()) {
+ ClassWalker<A, IvarOffsetOptimizer<A> > classVisitor(*this);
+ classVisitor.walk(cache, header);
+ } else {
+ //fprintf(stderr, "GC support present - skipped module\n");
+ }
}
}
};
typedef typename A::P P;
typedef typename A::P::uint_t pint_t;
+ uint32_t fOptimized;
+
friend class MethodListWalker<A, MethodListSorter<A> >;
void visitMethodList(objc_method_list_t<A> *mlist)
{
typename objc_method_t<A>::SortBySELAddress sorter;
std::stable_sort(mlist->begin(), mlist->end(), sorter);
mlist->setFixedUp();
+ fOptimized++;
}
public:
+ MethodListSorter() : fOptimized(0) { }
+
+ size_t optimized() const { return fOptimized; }
void optimize(SharedCache<A>* cache, macho_header<P>* header)
{
MethodListWalker<A, MethodListSorter<A> > mw(*this);
- mw.walk(cache, header);
+ mw.walk(cache, header, false /* don't sort protocol method lists*/);
}
};
-// Attach categories to classes in the same framework.
-// Merge method and protocol and property lists.
template <typename A>
-class CategoryAttacher {
+class HeaderInfoOptimizer {
typedef typename A::P P;
typedef typename A::P::uint_t pint_t;
- uint8_t *mBytes;
- ssize_t mBytesFree;
- ssize_t mBytesUsed;
-
- size_t mCategoriesAttached;
+ objc_header_info_t<A>* fHinfos;
+ size_t fCount;
- bool segmentContainsPointer(SharedCache<A>* cache,
- const macho_segment_command<P>* seg, void *ptr)
- {
- if (!seg) return false;
- void *start = (void*)
- cache->mappedAddressForVMAddress(seg->vmaddr());
- void *end = (uint8_t *)start + seg->filesize();
- return (ptr >= start && ptr < end);
- }
+public:
+ HeaderInfoOptimizer() : fHinfos(0), fCount(0) { }
- bool headerContainsPointer(SharedCache<A>* cache,
- macho_header<P>* header, void *ptr)
+ const char *init(size_t count, uint8_t*& buf, size_t& bufSize)
{
- return
- segmentContainsPointer(cache, header->getSegment("__DATA"), ptr) ||
- segmentContainsPointer(cache, header->getSegment("__TEXT"), ptr) ||
- segmentContainsPointer(cache, header->getSegment("__OBJC"), ptr);
- }
-
- struct pointer_hash {
- size_t operator () (void* ptr) const {
- return __gnu_cxx::hash<long>()((long)ptr);
- }
- };
-
- typedef std::deque<objc_category_t<A>*> CategoryList;
- typedef std::vector<uint64_t> CategoryRefs;
-
- struct ClassChanges {
- CategoryList categories;
- CategoryRefs catrefs;
-
- objc_method_list_t<A>* instanceMethods;
- objc_method_list_t<A>* classMethods;
- objc_protocol_list_t<A>* protocols;
- objc_property_list_t<A>* instanceProperties;
-
- ClassChanges()
- : instanceMethods(NULL), classMethods(NULL),
- protocols(NULL), instanceProperties(NULL)
- { }
-
- ~ClassChanges() {
- if (instanceMethods) delete instanceMethods;
- if (classMethods) delete classMethods;
- if (protocols) delete protocols;
- if (instanceProperties) delete instanceProperties;
- }
- };
-
- typedef __gnu_cxx::hash_map<objc_class_t<A>*, ClassChanges, pointer_hash> ClassMap;
-
- class RangeArray {
- typedef std::pair<uint8_t*,uint32_t> Range;
- std::deque<Range> ranges;
+ if (count == 0) return NULL;
- class SizeFits {
- private:
- uint32_t mSize;
- public:
- SizeFits(uint32_t size) : mSize(size) { }
- bool operator() (const Range& r) {
- return r.second >= mSize;
- }
- };
-
- struct AddressComp {
- bool operator() (const Range& lhs, const Range& rhs) {
- return (lhs.first < rhs.first);
- }
- };
- public:
- RangeArray() { }
- void add(void* p, uint32_t size) {
- add(Range((uint8_t *)p, size));
+ if (bufSize < 2*sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>)) {
+ return "libobjc's read/write section is too small (metadata not optimized)";
}
- void add(const Range& r) {
- // find insertion point
- std::deque<Range>::iterator iter;
- iter = upper_bound(ranges.begin(), ranges.end(), r, AddressComp());
- // coalesce
- // fixme doesn't fully coalesce if new range exactly fills a gap
- if (iter != ranges.begin()) {
- std::deque<Range>::iterator prev = iter - 1;
- if ((*prev).first + (*prev).second == r.first) {
- (*prev).second += r.second;
- return;
- }
- }
- if (iter != ranges.end() && iter+1 != ranges.end()) {
- std::deque<Range>::iterator next = iter + 1;
- if (r.first + r.second == (*next).first) {
- (*next).second += r.second;
- (*next).first = r.first;
- return;
- }
- }
- ranges.insert(iter, r);
- }
-
- uint8_t* remove(uint32_t size) {
- // first-fit search
- // this saves 50-75% of space overhead;
- // a better algorithm might do better
-
- std::deque<Range>::iterator iter;
- iter = find_if(ranges.begin(), ranges.end(), SizeFits(size));
- if (iter == ranges.end()) {
- return NULL;
- }
- Range& found = *iter;
- uint8_t *result = found.first;
- if (found.second > size) {
- // keep leftovers
- found.first += size;
- found.second -= size;
- } else {
- ranges.erase(iter);
- }
+ uint32_t *buf32 = (uint32_t *)buf;
+ A::P::E::set32(buf32[0], count);
+ A::P::E::set32(buf32[1], sizeof(objc_header_info_t<A>));
+ fHinfos = (objc_header_info_t<A>*)(buf32+2);
- return result;
- }
- };
+ size_t total = sizeof(uint32_t) + count*sizeof(objc_header_info_t<A>);
+ buf += total;
+ bufSize -= total;
- void copyMethods(typename objc_method_list_t<A>::method_iterator& dst,
- const objc_method_list_t<A>* srcList)
- {
- objc_method_list_t<A>::method_iterator::
- overwrite(dst, srcList);
+ return NULL;
}
- void copyProperties(typename objc_property_list_t<A>::property_iterator& dst,
- const objc_property_list_t<A>* srcList)
- {
- objc_property_list_t<A>::property_iterator::
- overwrite(dst, srcList);
+ void update(SharedCache<A>* cache, const macho_header<P>* mh, std::vector<void*>& pointersInData)
+ {
+ objc_header_info_t<A>* hi = new(&fHinfos[fCount++]) objc_header_info_t<A>(cache, mh);
+ hi->addPointers(pointersInData);
}
- void copyProtocols(objc_protocol_list_t<A>* dst, pint_t& dstIndex,
- const objc_protocol_list_t<A>* src)
+ objc_header_info_t<A>* hinfoForHeader(SharedCache<A>* cache, const macho_header<P>* mh)
{
- dst->overwrite(dstIndex, src);
- }
-
- class InSet
- {
- public:
- InSet(std::set<void*>& deadPointers) : _deadPointers(deadPointers) {}
-
- bool operator()(void* ptr) const {
- return ( _deadPointers.count(ptr) != 0 );
- }
-
- private:
- std::set<void*>& _deadPointers;
- };
-
-public:
-
- CategoryAttacher(uint8_t *bytes, ssize_t bytesFree)
- : mBytes(bytes), mBytesFree(bytesFree)
- , mBytesUsed(0), mCategoriesAttached(0)
- { }
-
- size_t count() const { return mCategoriesAttached; }
-
- const char *optimize(SharedCache<A>* cache, macho_header<P>* header, std::vector<void*>& pointersInData)
- {
- // Build class=>cateories mapping.
- // Disregard target classes that aren't in this binary.
-
- ClassMap map;
-
- PointerSection<A, objc_category_t<A> *>
- nlcatsect(cache, header, "__DATA", "__objc_nlcatlist");
- PointerSection<A, objc_category_t<A> *>
- catsect(cache, header, "__DATA", "__objc_catlist");
- for (pint_t i = 0; i < catsect.count(); i++) {
- objc_category_t<A> *cat = catsect.get(i);
- objc_class_t<A> *cls = cat->getClass(cache);
- if (!cls) continue;
- if (!headerContainsPointer(cache, header, cls)) continue;
- if ( nlcatsect.count() !=0 ) {
- // don't optimize categories also in __objc_nlcatlist
- bool alsoInNlcatlist = false;
- for (pint_t nli = 0; nli < nlcatsect.count(); nli++) {
- if ( nlcatsect.get(nli) == cat ) {
- //fprintf(stderr, "skipping cat in __objc_nlcatlist for mh=%p\n", header);
- alsoInNlcatlist = true;
- break;
- }
- }
- if ( alsoInNlcatlist )
- continue;
- }
-
- // The LAST category found is the FIRST to be processed later.
- map[cls].categories.push_front(cat);
-
- // We don't care about the category reference order.
- map[cls].catrefs.push_back(i);
- }
-
- if (map.size() == 0) {
- // No attachable categories.
- return NULL;
- }
-
- // Process each class.
- // Each class is all-or-nothing: either all of its categories
- // are attached successfully, or none of them are. This preserves
- // cache validity if we run out of space for more reallocations.
-
- // unusedMemory stores memory ranges evacuated by now-unused metadata.
- // It is available for re-use by other newly-added metadata.
- // fixme could packing algorithm be improved?
- RangeArray unusedMemory;
-
- ssize_t reserve = 0;
-
- // First: build new aggregated lists on the heap.
- // Require enough space in mBytes for all of it.
-
- std::set<void*> pointersToRemove;
- for (typename ClassMap::iterator i = map.begin();
- i != map.end();
- ++i)
- {
- objc_class_t<A>* cls = i->first;
- objc_class_t<A>* meta = cls->getIsa(cache);
- ClassChanges& changes = i->second;
- CategoryList& cats = changes.categories;
-
- // Count memory needed for all categories on this class.
-
- uint32_t methodEntsize = 0;
- uint32_t propertyEntsize = 0;
- objc_method_list_t<A>* mlist;
- objc_property_list_t<A>* proplist;
- objc_protocol_list_t<A>* protolist;
- uint32_t instanceMethodsCount = 0;
- uint32_t classMethodsCount = 0;
- uint32_t instancePropertyCount = 0;
- pint_t protocolCount = 0;
- bool addedInstanceMethods = false;
- bool addedClassMethods = false;
- bool addedInstanceProperties = false;
- bool addedProtocols = false;
-
- mlist = cls->getMethodList(cache);
- if (mlist) {
- instanceMethodsCount = mlist->getCount();
- methodEntsize =
- std::max(methodEntsize, mlist->getEntsize());
- }
-
- mlist = meta->getMethodList(cache);
- if (mlist) {
- classMethodsCount = mlist->getCount();
- methodEntsize =
- std::max(methodEntsize, mlist->getEntsize());
- }
-
- proplist = cls->getPropertyList(cache);
- if (proplist) {
- instancePropertyCount = proplist->getCount();
- propertyEntsize =
- std::max(propertyEntsize, proplist->getEntsize());
- }
-
- protolist = cls->getProtocolList(cache);
- if (protolist) {
- protocolCount = protolist->getCount();
- }
-
- typename CategoryList::iterator j;
- for (j = cats.begin(); j != cats.end(); ++j) {
- objc_category_t<A>* cat = *j;
-
- mlist = cat->getInstanceMethods(cache);
- if (mlist && mlist->getCount() > 0) {
- addedInstanceMethods = true;
- instanceMethodsCount += mlist->getCount();
- methodEntsize =
- std::max(methodEntsize, mlist->getEntsize());
- }
-
- mlist = cat->getClassMethods(cache);
- if (mlist && mlist->getCount() > 0) {
- addedClassMethods = true;
- classMethodsCount += mlist->getCount();
- methodEntsize =
- std::max(methodEntsize, mlist->getEntsize());
- }
-
- proplist = cat->getInstanceProperties(cache);
- if (proplist && proplist->getCount() > 0) {
- addedInstanceProperties = true;
- instancePropertyCount += proplist->getCount();
- propertyEntsize =
- std::max(propertyEntsize, proplist->getEntsize());
- }
-
- protolist = cat->getProtocols(cache);
- if (protolist && protolist->getCount() > 0) {
- addedProtocols = true;
- protocolCount += protolist->getCount();
- }
- }
-
- // Allocate memory for aggregated lists.
- // Reserve the same amount of space from mBytes.
-
- if (addedInstanceMethods) {
- changes.instanceMethods = objc_method_list_t<A>::newMethodList(instanceMethodsCount, methodEntsize);
- reserve = P::round_up(reserve + changes.instanceMethods->byteSize());
- }
- if (addedClassMethods) {
- changes.classMethods = objc_method_list_t<A>::newMethodList(classMethodsCount, methodEntsize);
- reserve = P::round_up(reserve + changes.classMethods->byteSize());
- }
- if (addedInstanceProperties) {
- changes.instanceProperties = objc_property_list_t<A>::newPropertyList(instancePropertyCount, propertyEntsize);
- reserve = P::round_up(reserve + changes.instanceProperties->byteSize());
- }
- if (addedProtocols) {
- changes.protocols = objc_protocol_list_t<A>::newProtocolList(protocolCount);
- reserve = P::round_up(reserve + changes.protocols->byteSize());
- }
-
- // Merge. The LAST category's contents ends up FIRST in each list.
- // The aggregated lists are not sorted; a future pass does that.
-
- typename objc_method_list_t<A>::method_iterator newInstanceMethods;
- typename objc_method_list_t<A>::method_iterator newClassMethods;
- typename objc_property_list_t<A>::property_iterator newInstanceProperties;
- pint_t newProtocolIndex;
-
- if (addedInstanceMethods) {
- newInstanceMethods = changes.instanceMethods->begin();
- }
- if (addedClassMethods) {
- newClassMethods = changes.classMethods->begin();
- }
- if (addedInstanceProperties) {
- newInstanceProperties = changes.instanceProperties->begin();
- }
- if (addedProtocols) {
- newProtocolIndex = 0;
- }
-
- for (j = cats.begin(); j != cats.end(); ++j) {
- objc_category_t<A>* cat = *j;
-
- mlist = cat->getInstanceMethods(cache);
- if (mlist) {
- copyMethods(newInstanceMethods, mlist);
- mlist->getPointers(pointersToRemove);
- unusedMemory.add(mlist, mlist->byteSize());
- }
-
- mlist = cat->getClassMethods(cache);
- if (mlist) {
- copyMethods(newClassMethods, mlist);
- mlist->getPointers(pointersToRemove);
- unusedMemory.add(mlist, mlist->byteSize());
- }
-
- proplist = cat->getInstanceProperties(cache);
- if (proplist) {
- copyProperties(newInstanceProperties, proplist);
- proplist->getPointers(pointersToRemove);
- unusedMemory.add(proplist, proplist->byteSize());
- }
-
- protolist = cat->getProtocols(cache);
- if (protolist) {
- copyProtocols(changes.protocols, newProtocolIndex, protolist);
- protolist->getPointers(pointersToRemove);
- unusedMemory.add(protolist, protolist->byteSize());
- }
-
- cat->getPointers(pointersToRemove);
- unusedMemory.add(cat, sizeof(*cat));
- }
-
- if (addedInstanceMethods && (mlist = cls->getMethodList(cache))) {
- copyMethods(newInstanceMethods, mlist);
- mlist->getPointers(pointersToRemove);
- unusedMemory.add(mlist, mlist->byteSize());
- }
- if (addedClassMethods && (mlist = meta->getMethodList(cache))) {
- copyMethods(newClassMethods, mlist);
- mlist->getPointers(pointersToRemove);
- unusedMemory.add(mlist, mlist->byteSize());
- }
- if (addedInstanceProperties && (proplist = cls->getPropertyList(cache))) {
- copyProperties(newInstanceProperties, proplist);
- proplist->getPointers(pointersToRemove);
- unusedMemory.add(proplist, proplist->byteSize());
- }
- if (addedProtocols && (protolist = cls->getProtocolList(cache))) {
- copyProtocols(changes.protocols, newProtocolIndex, protolist);
- protolist->getPointers(pointersToRemove);
- unusedMemory.add(protolist, protolist->byteSize());
- }
+ // fixme could be binary search
+ pint_t mh_vmaddr = cache->VMAddressForMappedAddress(mh);
+ for (size_t i = 0; i < fCount; i++) {
+ objc_header_info_t<A>* hi = &fHinfos[i];
+ if (hi->header_vmaddr() == mh_vmaddr) return hi;
}
-
- if (reserve > mBytesFree) {
- return "insufficient space for category data (metadata not optimized)";
- }
-
- // update cache slide info and remove areas now longer containing pointers
- //fprintf(stderr, "found %lu pointers in objc structures being moved\n", pointersToRemove.size());
- pointersInData.erase(std::remove_if(pointersInData.begin(), pointersInData.end(), InSet(pointersToRemove)), pointersInData.end());
-
-
- // All lists are now built.
- // mBytes is big enough to hold everything if necessary.
- // Everything in unusedMemory is now available for re-use.
- // The original metadata is still untouched.
-
- // Second: write lists into mBytes and unusedMemory,
- // then disconnect categories.
-
- for (typename ClassMap::iterator i = map.begin();
- i != map.end();
- ++i)
- {
- objc_class_t<A>* cls = i->first;
- objc_class_t<A>* meta = cls->getIsa(cache);
- ClassChanges& changes = i->second;
-
- // Write lists.
-
- if (changes.instanceMethods) {
- uint8_t *bytes;
- uint32_t size = changes.instanceMethods->byteSize();
- if (! (bytes = unusedMemory.remove(size))) {
- bytes = mBytes + mBytesUsed;
- mBytesFree -= size;
- mBytesUsed += size;
- }
- memcpy(bytes, changes.instanceMethods, size);
- objc_method_list_t<A>::addPointers(bytes, pointersInData);
- cls->setMethodList(cache, (objc_method_list_t<A> *)bytes);
- cls->addMethodListPointer(cache, pointersInData);
- }
-
- if (changes.classMethods) {
- uint8_t *bytes;
- uint32_t size = changes.classMethods->byteSize();
- if (! (bytes = unusedMemory.remove(size))) {
- bytes = mBytes + mBytesUsed;
- mBytesFree -= size;
- mBytesUsed += size;
- }
- memcpy(bytes, changes.classMethods, size);
- objc_method_list_t<A>::addPointers(bytes, pointersInData);
- meta->setMethodList(cache, (objc_method_list_t<A> *)bytes);
- meta->addMethodListPointer(cache, pointersInData);
- }
-
- if (changes.instanceProperties) {
- uint8_t *bytes;
- uint32_t size = changes.instanceProperties->byteSize();
- if (! (bytes = unusedMemory.remove(size))) {
- bytes = mBytes + mBytesUsed;
- mBytesFree -= size;
- mBytesUsed += size;
- }
- memcpy(bytes, changes.instanceProperties, size);
- objc_property_list_t<A>::addPointers(bytes, pointersInData);
- cls->setPropertyList(cache, (objc_property_list_t<A> *)bytes);
- cls->addPropertyListPointer(cache, pointersInData);
- }
-
- if (changes.protocols) {
- uint8_t *bytes;
- uint32_t size = changes.protocols->byteSize();
- if (! (bytes = unusedMemory.remove(size))) {
- bytes = mBytes + mBytesUsed;
- mBytesFree -= size;
- mBytesUsed += size;
- }
- memcpy(bytes, changes.protocols, size);
- cls->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
- objc_protocol_list_t<A>::addPointers(bytes, pointersInData);
- cls->addProtocolListPointer(cache, pointersInData);
- meta->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
- meta->addProtocolListPointer(cache, pointersInData);
- }
-
- // Disavow all knowledge of the categories.
-
- for (typename CategoryRefs::iterator j = changes.catrefs.begin();
- j != changes.catrefs.end();
- ++j)
- {
- catsect.set(*j, 0);
- }
-
- mCategoriesAttached += changes.categories.size();
- }
-
- catsect.removeNulls();
-
return NULL;
}
-
- ssize_t bytesUsed() { return mBytesUsed; }
};
/* -*- 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@
*
macho_segment_command<P>* linkEditSegCmd = NULL;
macho_symtab_command<P>* symtab = NULL;
macho_dysymtab_command<P>* dynamicSymTab = NULL;
+ macho_linkedit_data_command<P>* functionStarts = NULL;
+ macho_linkedit_data_command<P>* dataInCode = NULL;
for (uint32_t i = 0; i < cmd_count; ++i) {
if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
// update segment/section file offsets
else if ( cmd->cmd() == LC_DYSYMTAB ) {
dynamicSymTab = (macho_dysymtab_command<P>*)cmd;
}
+ else if ( cmd->cmd() == LC_FUNCTION_STARTS ) {
+ functionStarts = (macho_linkedit_data_command<P>*)cmd;
+ }
+ else if ( cmd->cmd() == LC_DATA_IN_CODE ) {
+ dataInCode = (macho_linkedit_data_command<P>*)cmd;
+ }
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
fprintf(stderr, "LC_DYSYMTAB not found\n");
return -1;
}
+
+ const uint32_t newFunctionStartsOffset = linkEditSegCmd->fileoff();
+ uint32_t functionStartsSize = 0;
+ if ( functionStarts != NULL ) {
+ // copy function starts from original cache file to new mapped dylib file
+ functionStartsSize = functionStarts->datasize();
+ memcpy((char*)mh + newFunctionStartsOffset, (char*)mapped_cache + functionStarts->dataoff(), functionStartsSize);
+ }
+ const uint32_t newDataInCodeOffset = (newFunctionStartsOffset + functionStartsSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
+ uint32_t dataInCodeSize = 0;
+ if ( dataInCode != NULL ) {
+ // copy data-in-code info from original cache file to new mapped dylib file
+ dataInCodeSize = dataInCode->datasize();
+ memcpy((char*)mh + newDataInCodeOffset, (char*)mapped_cache + dataInCode->dataoff(), dataInCodeSize);
+ }
// copy symbol entries and strings from original cache file to new mapped dylib file
- const uint32_t newSymTabOffset = linkEditSegCmd->fileoff();
+ const uint32_t newSymTabOffset = (newDataInCodeOffset + dataInCodeSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
const uint32_t newIndSymTabOffset = newSymTabOffset + symtab->nsyms()*sizeof(macho_nlist<P>);
const uint32_t newStringPoolOffset = newIndSymTabOffset + dynamicSymTab->nindirectsyms()*sizeof(uint32_t);
macho_nlist<P>* const newSymTabStart = (macho_nlist<P>*)(((uint8_t*)mh) + newSymTabOffset);
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);
}
-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;
dylib_create_func = dylib_maker<x86>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64") == 0 )
dylib_create_func = dylib_maker<x86_64>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 ppc") == 0 )
- dylib_create_func = dylib_maker<ppc>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv5") == 0 )
dylib_create_func = dylib_maker<arm>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv6") == 0 )
dylib_create_func = dylib_maker<arm>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7") == 0 )
dylib_create_func = dylib_maker<arm>;
+ else if ( strncmp((char*)mapped_cache, "dyld_v1 armv7", 14) == 0 )
+ dylib_create_func = dylib_maker<arm>;
else {
fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
munmap(mapped_cache, statbuf.st_size);
// 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);
__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);
#if 0
+
+typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
+ void (^progress)(unsigned current, unsigned total));
+
int main(int argc, const char* argv[])
{
if ( argc != 3 ) {
fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
return 1;
}
-
- int result = dyld_shared_cache_extract_dylibs_progress(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
+
+ void* handle = dlopen("/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
+ if ( handle == NULL ) {
+ fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
+ return 1;
+ }
+
+ extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
+ if ( proc == NULL ) {
+ fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
+ return 1;
+ }
+
+ int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
return 0;
}
#endif
-
+
+
return dyld::walkImages<x86>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 x86_64") == 0 )
return dyld::walkImages<x86_64>(cache, callback);
- else if ( strcmp((char*)cache, "dyld_v1 ppc") == 0 )
- return dyld::walkImages<ppc>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv5") == 0 )
return dyld::walkImages<arm>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv6") == 0 )
return dyld::walkImages<arm>(cache, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv7") == 0 )
return dyld::walkImages<arm>(cache, callback);
+ else if ( strncmp((char*)cache, "dyld_v1 armv7", 14) == 0 )
+ return dyld::walkImages<arm>(cache, callback);
else
return -1;
}
+++ /dev/null
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <Availability.h>
-
-#define NO_ULEB 1
-#include "dyld_cache_format.h"
-#include "Architectures.hpp"
-#include "MachOFileAbstraction.hpp"
-#include "CacheFileAbstraction.hpp"
-
-#include "dsc_slider.h"
-
-int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) )
-{
- int fd = open(path, O_RDONLY, 0);
- if ( fd == -1 ) {
- (*logProc)("open(%s) failed, errno=%d\n", path, errno);
- return -1;
- }
- (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
-
- uint8_t buffer[4096];
- if ( read(fd, buffer, 4096) != 4096 ) {
- (*logProc)("read(%s) failed, errno=%d\n", path, errno);
- close(fd);
- return -1;
- }
- bool has64BitPointers = false;
- bool isBigEndian = false;
- uint64_t startReadOnlySharedRegion = 0;
- uint64_t endReadOnlySharedRegion = 0;
- uint64_t startReadWriteSharedRegion = 0;
- uint64_t endReadWriteSharedRegion = 0;
- if ( strcmp((char*)buffer, "dyld_v1 i386") == 0 ) {
- has64BitPointers = false;
- isBigEndian = false;
- }
- else if ( strcmp((char*)buffer, "dyld_v1 x86_64") == 0 ) {
- has64BitPointers = true;
- isBigEndian = false;
- startReadOnlySharedRegion = 0x7FFF80000000LL;
- endReadOnlySharedRegion = 0x7FFFC0000000LL;
- startReadWriteSharedRegion = 0x7FFF70000000LL;
- endReadWriteSharedRegion = 0x7FFF80000000LL;
- }
- else if ( strcmp((char*)buffer, "dyld_v1 ppc") == 0 ) {
- has64BitPointers = false;
- isBigEndian = true;
- }
- else if ( strcmp((char*)buffer, "dyld_v1 armv5") == 0 ) {
- has64BitPointers = false;
- isBigEndian = false;
- startReadOnlySharedRegion = 0x30000000LL;
- endReadOnlySharedRegion = 0x3E000000LL;
- startReadWriteSharedRegion = 0x3E000000LL;
- endReadWriteSharedRegion = 0x40000000LL;
- }
- else if ( strcmp((char*)buffer, "dyld_v1 armv6") == 0 ) {
- has64BitPointers = false;
- isBigEndian = false;
- startReadOnlySharedRegion = 0x30000000LL;
- endReadOnlySharedRegion = 0x3E000000LL;
- startReadWriteSharedRegion = 0x3E000000LL;
- endReadWriteSharedRegion = 0x40000000LL;
- }
- else if ( strcmp((char*)buffer, "dyld_v1 armv7") == 0 ) {
- has64BitPointers = false;
- isBigEndian = false;
- startReadOnlySharedRegion = 0x30000000LL;
- endReadOnlySharedRegion = 0x3E000000LL;
- startReadWriteSharedRegion = 0x3E000000LL;
- endReadWriteSharedRegion = 0x40000000LL;
- }
- else {
- (*logProc)("file %s is not a known dyld shared cache file\n", path);
- close(fd);
- return -1;
- }
-#if __BIG_ENDIAN__
- bool swap = !isBigEndian;
-#else
- bool swap = isBigEndian;
-#endif
-
- const dyld_cache_header* header = (dyld_cache_header*)buffer;
- uint32_t mappingOffset = swap ? OSSwapInt32(header->mappingOffset) : header->mappingOffset;
- if ( mappingOffset < 0x48 ) {
- (*logProc)("dyld shared cache file %s is old format\n", path);
- close(fd);
- return -1;
- }
-
- uint32_t mappingCount = swap ? OSSwapInt32(header->mappingCount) : header->mappingCount;
- if ( mappingCount != 3 ) {
- (*logProc)("dyld shared cache file %s has wrong mapping count\n", path);
- close(fd);
- return -1;
- }
-
- uint64_t slidePointersOffset = swap ? OSSwapInt64(header->slidePointersOffset) : header->slidePointersOffset;
- uint64_t slidePointersSize = swap ? OSSwapInt64(header->slidePointersSize) : header->slidePointersSize;
- if ( (slidePointersOffset == 0) || (slidePointersSize == 0) ) {
- (*logProc)("dyld shared cache file %s is missing slide information\n", path);
- close(fd);
- return -1;
- }
-
- // read slide info
- void* slideInfo = malloc(slidePointersSize);
- if ( slideInfo == NULL ) {
- (*logProc)("malloc(%llu) failed\n", slidePointersSize);
- close(fd);
- return -1;
- }
- int64_t amountRead = pread(fd, slideInfo, slidePointersSize, slidePointersOffset);
- if ( amountRead != (int64_t)slidePointersSize ) {
- (*logProc)("slide info pread(fd, buf, %llu, %llu) failed\n", slidePointersSize, slidePointersOffset);
- close(fd);
- return -1;
- }
-
- // read all DATA
- const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)&buffer[mappingOffset];
- uint64_t dataFileOffset = swap ? OSSwapInt64(mappings[1].fileOffset) : mappings[1].fileOffset;
- uint64_t dataSize = swap ? OSSwapInt64(mappings[1].size) : mappings[1].size;
- uint8_t* data = (uint8_t*)malloc(dataSize);
- amountRead = pread(fd, data, dataSize, dataFileOffset);
- if ( amountRead != (int64_t)dataSize ) {
- (*logProc)("data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
- close(fd);
- return -1;
- }
-
- // close read-only file
- close(fd);
-
- // extract current slide
- uint64_t headerDataUses;
- if ( has64BitPointers ) {
- headerDataUses = *((uint64_t*)data);
- if ( swap )
- headerDataUses = OSSwapInt64(headerDataUses);
- }
- else {
- uint32_t temp = *((uint32_t*)data);
- if ( swap )
- temp = OSSwapInt32(temp);
- headerDataUses = temp;
- }
- uint64_t textAddress = swap ? OSSwapInt64(mappings[0].address) : mappings[0].address;
- uint32_t currentSlide = headerDataUses - textAddress;
- (*logProc)("currentSlide=0x%08X\n", currentSlide);
-
- // find read-only space
- uint64_t linkeditAddress = swap ? OSSwapInt64(mappings[2].address) : mappings[2].address;
- uint64_t linkeditSize = swap ? OSSwapInt64(mappings[2].size) : mappings[2].size;
- uint64_t linkeditEnd = linkeditAddress + linkeditSize;
- uint64_t roSpace = endReadOnlySharedRegion - linkeditEnd;
- (*logProc)("ro space=0x%08llX\n", roSpace);
-
- // find read-write space
- uint64_t dataAddress = swap ? OSSwapInt64(mappings[1].address) : mappings[1].address;
- uint64_t dataEnd = dataAddress + dataSize;
- uint64_t rwSpace = endReadWriteSharedRegion - dataEnd;
- (*logProc)("rw space=0x%08llX\n", rwSpace);
-
- // choose new random slide
- uint32_t slideSpace = rwSpace;
- if ( roSpace < rwSpace )
- slideSpace = roSpace;
- uint32_t newSlide = (arc4random() % slideSpace) & (-4096);
- (*logProc)("newSlide=0x%08X\n", newSlide);
- int32_t slideAdjustment = newSlide - currentSlide;
-
- // update DATA with slide info
- uint64_t offsetInCacheFile = 0;
- const uint8_t* infoStart = (uint8_t*)slideInfo;
- const uint8_t* infoEnd = infoStart + slidePointersSize;
- for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
- uint64_t delta = 0;
- uint32_t shift = 0;
- bool more = true;
- do {
- uint8_t byte = *p++;
- delta |= ((byte & 0x7F) << shift);
- shift += 7;
- if ( byte < 0x80 ) {
- offsetInCacheFile += delta;
- // verify in DATA range
- if ( (offsetInCacheFile < dataFileOffset) || (offsetInCacheFile > (dataFileOffset+dataSize)) ) {
- (*logProc)("pointer offset 0x%llX outside DATA range\n", offsetInCacheFile);
- return -1;
- }
- uint32_t offsetInData = offsetInCacheFile - dataFileOffset;
- if ( has64BitPointers ) {
- uint64_t value64 = *((uint64_t*)(&data[offsetInData]));
- if ( swap )
- value64 = OSSwapInt64(value64);
- value64 += slideAdjustment;
- if ( swap )
- value64 = OSSwapInt64(value64);
- *((uint64_t*)(&data[offsetInData])) = value64;
- }
- else {
- uint64_t value32 = *((uint32_t*)(&data[offsetInData]));
- if ( swap )
- value32 = OSSwapInt32(value32);
- value32 += slideAdjustment;
- if ( swap )
- value32 = OSSwapInt32(value32);
- *((uint32_t*)(&data[offsetInData])) = value32;
- }
- //(*logProc)("update pointer at offset 0x%08X", offsetInData);
- more = false;
- }
- } while (more);
- }
- free(slideInfo);
- slideInfo = NULL;
-
- // re-open cache file and overwrite DATA range
- fd = open(path, O_RDWR, 0);
- if ( fd == -1 ) {
- (*logProc)("open(%s) failed, errno=%d\n", path, errno);
- return -1;
- }
- (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
- uint64_t amountWrote = pwrite(fd, data, dataSize, dataFileOffset);
- if ( amountWrote != dataSize ) {
- (*logProc)("data pwrite(fd, buf, %llu, %llu) failed\n", data, dataSize);
- close(fd);
- return -1;
- }
- close(fd);
-
- // re-open and re-read to verify write
- fd = open(path, O_RDONLY, 0);
- if ( fd == -1 ) {
- (*logProc)("verify open(%s) failed, errno=%d\n", path, errno);
- return -1;
- }
- (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
- uint8_t* dataVerify = (uint8_t*)malloc(dataSize);
- amountRead = pread(fd, dataVerify, dataSize, dataFileOffset);
- if ( amountRead != (int64_t)dataSize ) {
- (*logProc)("verify data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
- close(fd);
- return -1;
- }
- close(fd);
- if ( memcmp(data, dataVerify, dataSize) != 0 ) {
- (*logProc)("data update verification failed\n");
- return -1;
- }
- free(data);
- free(dataVerify);
-
-
- // success
- return 0;
-}
-
-
-#if 0
-static void logger(const char* format, ...)
-{
- va_list list;
- va_start(list, format);
- fprintf(stderr, "error: ");
- vfprintf(stderr, format, list);
-}
-
-
-int main(int argc, const char* argv[])
-{
- return update_dyld_shared_cache_load_address(argv[1], logger);
-}
-#endif
-
-
+++ /dev/null
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//
-// This function is called with a path to a dyld shared cache file. It will update the shared cache file
-// in place. The update randomizes the load address when the shared cache file is later used by dyld.
-//
-// On success, the return value is zero.
-// On failure the return value is non-zero and an explanation error was written to the logProc callback.
-//
-extern int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) );
-
-
-#ifdef __cplusplus
-}
-#endif
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
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
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);
}
const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)mapped_cache;
if ( (strcmp(header->magic(), "dyld_v1 x86_64") != 0)
&& (strcmp(header->magic(), "dyld_v1 armv6") != 0)
- && (strcmp(header->magic(), "dyld_v1 armv7") != 0) ) {
+ && (strcmp(header->magic(), "dyld_v1 armv7") != 0)
+ && (strcmp(header->magic(), "dyld_v1 armv7f") != 0)
+ && (strcmp(header->magic(), "dyld_v1 armv7k") != 0) ) {
fprintf(stderr, "Error: unrecognized dyld shared cache magic or arch does not support sliding\n");
exit(1);
}
callback = segment_callback<x86>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64") == 0 )
callback = segment_callback<x86_64>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 ppc") == 0 )
- callback = segment_callback<ppc>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv5") == 0 )
callback = segment_callback<arm>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv6") == 0 )
callback = segment_callback<arm>;
else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7") == 0 )
callback = segment_callback<arm>;
+ else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7f") == 0 )
+ callback = segment_callback<arm>;
+ else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7k") == 0 )
+ callback = segment_callback<arm>;
else {
fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
exit(1);
#include "CacheFileAbstraction.hpp"
#define SELOPT_WRITE
-#include <objc/objc-selopt.h>
+#include "objc-shared-cache.h"
-#define FIRST_DYLIB_TEXT_OFFSET 0x5000
+#define FIRST_DYLIB_TEXT_OFFSET 0x7000
#define FIRST_DYLIB_DATA_OFFSET 0x1000
#ifndef LC_FUNCTION_STARTS
static void addRoot(const char* vpath, const std::set<ArchPair>& archs);
static void findSharedDylibs(ArchPair ap);
static ArchGraph* graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
- static void setFileSystemRoot(const char* root, bool usesOverlay) { fgFileSystemRoot = root; fgUsesOverlay = usesOverlay; }
+ static void setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
+ static void setFileSystemOverlay(const char* overlay) { fgFileSystemOverlay = overlay; }
static const char* archName(ArchPair ap);
ArchPair getArchPair() { return fArchPair; }
static std::map<ArchPair, ArchGraph*> fgPerArchGraph;
static const char* fgFileSystemRoot;
- static bool fgUsesOverlay;
+ static const char* fgFileSystemOverlay;
ArchPair fArchPair;
std::set<DependencyNode*> fRoots;
};
std::map<ArchPair, ArchGraph*> ArchGraph::fgPerArchGraph;
const char* ArchGraph::fgFileSystemRoot = "";
-bool ArchGraph::fgUsesOverlay = false;
+const char* ArchGraph::fgFileSystemOverlay = "";
void ArchGraph::addArchPair(ArchPair ap)
{
void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
{
- char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
+ //fprintf(stderr, "addRoot(%s)\n", vpath);
+ char completePath[MAXPATHLEN];
const char* path = NULL;
- if ( strlen(fgFileSystemRoot) == 0 ) {
- path = vpath;
+ // check -overlay path first
+ if ( fgFileSystemOverlay[0] != '\0' ) {
+ strcpy(completePath, fgFileSystemOverlay);
+ strcat(completePath, vpath); // assumes vpath starts with '/'
+ struct stat stat_buf;
+ if ( stat(completePath, &stat_buf) == 0 )
+ path = completePath;
}
- else {
+ // if not found in overlay, check for -root
+ if ( (path == NULL) && (fgFileSystemRoot[0] != '\0') ) {
strcpy(completePath, fgFileSystemRoot);
strcat(completePath, vpath); // assumes vpath starts with '/'
- if ( fgUsesOverlay ) {
- // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
- struct stat stat_buf;
- if ( stat(completePath, &stat_buf) == 0 )
- path = completePath;
- else
- path = vpath;
- }
- else {
- // using -root means alway redirect /usr/lib to /rootpath/usr/lib
+ struct stat stat_buf;
+ if ( stat(completePath, &stat_buf) == 0 )
path = completePath;
- }
}
+ if ( path == NULL )
+ path = vpath;
+
try {
+ //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &onlyArchs);
for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
try {
node->markNeededByRoot(NULL);
}
-// a virtual path does not have the fgFileSystemRoot prefix
// a virtual path does not have the fgFileSystemRoot prefix
ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
{
- if ( fgFileSystemRoot == NULL ) {
- return this->getNode(vpath);
- }
- else {
- char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
- strcpy(completePath, fgFileSystemRoot);
+ //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
+ char completePath[MAXPATHLEN];
+ if ( fgFileSystemOverlay[0] != '\0' ) {
+ // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
+ strcpy(completePath, fgFileSystemOverlay);
strcat(completePath, vpath); // assumes vpath starts with '/'
- if ( fgUsesOverlay ) {
- // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
- struct stat stat_buf;
- if ( stat(completePath, &stat_buf) == 0 )
- return this->getNode(completePath);
- else {
- // <rdar://problem/9279770> support when install name is a symlink
- if ( (lstat(vpath, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
- // requested path did not exist in /overlay, but leaf of path is a symlink in /
- char pathInSymLink[MAXPATHLEN];
- size_t res = readlink(vpath, pathInSymLink, sizeof(pathInSymLink));
- if ( res != -1 ) {
- pathInSymLink[res] = '\0';
- if ( pathInSymLink[0] != '/' ) {
- char symFullPath[MAXPATHLEN];
- strcpy(symFullPath, vpath);
- char* lastSlash = strrchr(symFullPath, '/');
- if ( lastSlash != NULL ) {
- strcpy(lastSlash+1, pathInSymLink);
- // (re)try looking for what symlink points to, but in /overlay
- return this->getNodeForVirtualPath(symFullPath);
- }
- }
- }
+ struct stat stat_buf;
+ if ( stat(completePath, &stat_buf) == 0 )
+ return this->getNode(completePath);
+ else {
+ // <rdar://problem/9279770> support when install name is a symlink
+ const char* pathToSymlink = vpath;
+ if ( fgFileSystemRoot[0] != '\0' ) {
+ strcpy(completePath, fgFileSystemRoot);
+ strcat(completePath, vpath);
+ pathToSymlink = completePath;
+ }
+ if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
+ // requested path did not exist in /overlay, but leaf of path is a symlink in /
+ char pathInSymLink[MAXPATHLEN];
+ size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
+ if ( res != -1 ) {
+ pathInSymLink[res] = '\0';
+ if ( pathInSymLink[0] != '/' ) {
+ char symFullPath[MAXPATHLEN];
+ strcpy(symFullPath, vpath);
+ char* lastSlash = strrchr(symFullPath, '/');
+ if ( lastSlash != NULL ) {
+ strcpy(lastSlash+1, pathInSymLink);
+ // (re)try looking for what symlink points to, but in /overlay
+ return this->getNodeForVirtualPath(symFullPath);
+ }
+ }
}
- return this->getNode(vpath);
}
}
- else {
- // using -root means always use /rootpath/usr/lib
- return this->getNode(completePath);
- }
}
+ if ( fgFileSystemRoot[0] != '\0' ) {
+ // using -root means always use /rootpath/usr/lib
+ strcpy(completePath, fgFileSystemRoot);
+ strcat(completePath, vpath); // assumes vpath starts with '/'
+ return this->getNode(completePath);
+ }
+ // not found in -overlay or -root not used
+ return this->getNode(vpath);
}
ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
{
+ //fprintf(stderr, "getNode(%s)\n", path);
// look up supplied path to see if node already exists
PathToNode::iterator pos = fNodes.find(path);
if ( pos != fNodes.end() )
fNodes[node->getLayout()->getID().name] = node;
// update fAliasesMap with symlinks found
const char* aliasPath = realPath;
- if ( (fgFileSystemRoot != NULL) && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+ if ( (fgFileSystemRoot != NULL) && (fgFileSystemRoot[0] != '\0') && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
aliasPath = &realPath[strlen(fgFileSystemRoot)];
}
+ // <rdar://problem/11192810> Too many aliases in -overlay mode
+ if ( (fgFileSystemOverlay != NULL) && (fgFileSystemOverlay[0] != '\0') && (strncmp(realPath, fgFileSystemOverlay, strlen(fgFileSystemOverlay)) == 0) ) {
+ aliasPath = &realPath[strlen(fgFileSystemOverlay)];
+ }
if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
fAliasesMap[strdup(aliasPath)] = node->getLayout()->getID().name;
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
}
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:
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";
}
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);
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);
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;
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();
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) {
uint32_t fSizeOfOldStringPoolInCombinedLinkedit;
uint32_t fOffsetOfFunctionStartsInCombinedLinkedit;
uint32_t fSizeOfFunctionStartsInCombinedLinkedit;
+ uint32_t fOffsetOfDataInCodeInCombinedLinkedit;
+ uint32_t fSizeOfDataInCodeInCombinedLinkedit;
uint32_t fLinkEditsTotalOptimizedSize;
};
-template <> cpu_type_t SharedCache<ppc>::arch() { return CPU_TYPE_POWERPC; }
template <> cpu_type_t SharedCache<x86>::arch() { return CPU_TYPE_I386; }
template <> cpu_type_t SharedCache<x86_64>::arch() { return CPU_TYPE_X86_64; }
template <> cpu_type_t SharedCache<arm>::arch() { return CPU_TYPE_ARM; }
-template <> uint64_t SharedCache<ppc>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
template <> uint64_t SharedCache<x86>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; }
template <> uint64_t SharedCache<arm>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
-template <> uint64_t SharedCache<ppc>::sharedRegionWritableStartAddress() { return 0xA0000000; }
template <> uint64_t SharedCache<x86>::sharedRegionWritableStartAddress() { return 0xAC000000; }
template <> uint64_t SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
template <> uint64_t SharedCache<arm>::sharedRegionWritableStartAddress() { return 0x3E000000; }
-template <> uint64_t SharedCache<ppc>::sharedRegionReadOnlySize() { return 0x10000000; }
template <> uint64_t SharedCache<x86>::sharedRegionReadOnlySize() { return 0x1C000000; }
template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlySize() { return 0x40000000; }
template <> uint64_t SharedCache<arm>::sharedRegionReadOnlySize() { return 0x0E000000; }
-template <> uint64_t SharedCache<ppc>::sharedRegionWritableSize() { return 0x10000000; }
template <> uint64_t SharedCache<x86>::sharedRegionWritableSize() { return 0x04000000; }
template <> uint64_t SharedCache<x86_64>::sharedRegionWritableSize() { return 0x10000000; }
template <> uint64_t SharedCache<arm>::sharedRegionWritableSize() { return 0x02000000; }
-template <> const char* SharedCache<ppc>::archName() { return "ppc"; }
template <> const char* SharedCache<x86>::archName() { return "i386"; }
template <> const char* SharedCache<x86_64>::archName() { return "x86_64"; }
template <> const char* SharedCache<arm>::archName() { return "arm"; }
-template <> const char* SharedCache<ppc>::cacheFileSuffix(bool optimized, const char*) { return optimized ? "ppc" : "rosetta"; }
template <> const char* SharedCache<x86>::cacheFileSuffix(bool, const char* archName) { return archName; }
template <> const char* SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
template <> const char* SharedCache<arm>::cacheFileSuffix(bool, const char* archName) { return archName; }
template <typename A>
-SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress)
+SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress)
: fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true),
fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
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());
}
// 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);
return proposedNewAddress;
}
-template <>
-uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
-{
- // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
- return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
-}
-
template <typename A>
void SharedCache<A>::assignNewBaseAddresses(bool verify)
}
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);
(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
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);
macho_dyld_info_command<P>* fDyldInfo;
macho_dysymtab_command<P>* fDynamicSymbolTable;
macho_linkedit_data_command<P>* fFunctionStarts;
+ macho_linkedit_data_command<P>* fDataInCode;
macho_symtab_command<P>* fSymbolTableLoadCommand;
const macho_nlist<P>* fSymbolTable;
const char* fStrings;
uint32_t fExternalRelocationsOffsetIntoNewLinkEdit;
uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit;
uint32_t fFunctionStartsOffsetInNewLinkEdit;
+ uint32_t fDataInCodeOffsetInNewLinkEdit;
};
template <typename A>
LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache<A>& sharedCache, uint8_t* newLinkEdit, StringPool& stringPool)
: fSharedCache(sharedCache), fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
- fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
+ fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fDataInCode(NULL),
+ fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
- fFunctionStartsOffsetInNewLinkEdit(0)
+ fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0)
{
fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
break;
case LC_FUNCTION_STARTS:
fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
+ case LC_DATA_IN_CODE:
+ fDataInCode = (macho_linkedit_data_command<P>*)cmd;
break;
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
}
+template <typename A>
+void LinkEditOptimizer<A>::copyDataInCode(uint32_t& offset)
+{
+ if ( fDataInCode != NULL ) {
+ fDataInCodeOffsetInNewLinkEdit = offset;
+ memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fDataInCode->dataoff()], fDataInCode->datasize());
+ offset += fDataInCode->datasize();
+ }
+}
+
+
template <typename A>
void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
{
if ( fFunctionStarts != NULL ) {
fFunctionStarts->set_dataoff(linkEditsFileOffset+fFunctionStartsOffsetInNewLinkEdit);
}
+ // update data-in-code info
+ if ( fDataInCode != NULL ) {
+ fDataInCode->set_dataoff(linkEditsFileOffset+fDataInCodeOffsetInNewLinkEdit);
+ }
// now remove load commands no longer needed
const macho_load_command<P>* srcCmd = cmds;
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:
}
fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit;
+ // copy data-in-code info
+ fOffsetOfDataInCodeInCombinedLinkedit = offset;
+ for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+ (*it)->copyDataInCode(offset);
+ }
+ fSizeOfDataInCodeInCombinedLinkedit = offset - fOffsetOfDataInCodeInCombinedLinkedit;
+
// copy indirect symbol tables
fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
}
-
template <typename A>
class ObjCSelectorUniquer
{
size_t count() const { return fCount; }
};
+
+template <typename A>
+class ClassListBuilder
+{
+private:
+ typedef typename A::P P;
+
+ objc_opt::string_map fClassNames;
+ objc_opt::class_map fClasses;
+ size_t fCount;
+ HeaderInfoOptimizer<A>& fHinfos;
+
+public:
+
+ ClassListBuilder(HeaderInfoOptimizer<A>& hinfos)
+ : fClassNames()
+ , fClasses()
+ , fCount(0)
+ , fHinfos(hinfos)
+ { }
+
+ void visitClass(SharedCache<A>* cache,
+ const macho_header<P>* header,
+ objc_class_t<A>* cls)
+ {
+ if (cls->isMetaClass(cache)) return;
+
+ const char *name = cls->getName(cache);
+ uint64_t name_vmaddr = cache->VMAddressForMappedAddress(name);
+ uint64_t cls_vmaddr = cache->VMAddressForMappedAddress(cls);
+ uint64_t hinfo_vmaddr = cache->VMAddressForMappedAddress(fHinfos.hinfoForHeader(cache, header));
+ fClassNames.insert(objc_opt::string_map::value_type(name, name_vmaddr));
+ fClasses.insert(objc_opt::class_map::value_type(name, std::pair<uint64_t, uint64_t>(cls_vmaddr, hinfo_vmaddr)));
+ fCount++;
+ }
+
+ objc_opt::string_map& classNames() {
+ return fClassNames;
+ }
+
+ objc_opt::class_map& classes() {
+ return fClasses;
+ }
+
+ size_t count() const { return fCount; }
+};
+
+
+static int percent(size_t num, size_t denom) {
+ if (denom) return (int)(num / (double)denom * 100);
+ else return 100;
+}
+
template <typename A>
void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
{
const char *err;
- size_t headerSize = sizeof(objc_opt::objc_opt_t);
if ( verbose ) {
fprintf(stderr, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
}
+ size_t headerSize = P::round_up(sizeof(objc_opt::objc_opt_t));
+ if (headerSize != sizeof(objc_opt::objc_opt_t)) {
+ warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
+ }
+
// Find libobjc's empty sections to fill in
const macho_section<P> *optROSection = NULL;
const macho_section<P> *optRWSection = NULL;
if ( strstr(it->layout->getFilePath(), "libobjc") != NULL ) {
const macho_header<P>* mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
optROSection = mh->getSection("__TEXT", "__objc_opt_ro");
- // __objc_selopt is old name for __objc_opt_ro
- if ( optROSection == NULL )
- optROSection = mh->getSection("__TEXT", "__objc_selopt");
optRWSection = mh->getSection("__DATA", "__objc_opt_rw");
break;
}
return;
}
- objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t*)mappedAddressForVMAddress(optROSection->addr());
- if (optROSection->size() < headerSize) {
+ if ( optRWSection == NULL ) {
+ warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
+ return;
+ }
+
+ uint8_t* optROData = (uint8_t*)mappedAddressForVMAddress(optROSection->addr());
+ size_t optRORemaining = optROSection->size();
+
+ uint8_t* optRWData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr());
+ size_t optRWRemaining = optRWSection->size();
+
+ if (optRORemaining < headerSize) {
warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
return;
}
+ objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t *)optROData;
+ optROData += headerSize;
+ optRORemaining -= headerSize;
if (E::get32(optROHeader->version) != objc_opt::VERSION) {
warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
return;
}
+ // Write nothing to optROHeader until everything else is written.
+ // If something fails below, libobjc will not use the section.
+
+ // Find objc-containing dylibs
+ std::vector<LayoutInfo> objcDylibs;
+ for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+ macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ if (mh->getSection("__DATA", "__objc_imageinfo") || mh->getSegment("__OBJC")) {
+ objcDylibs.push_back(*it);
+ }
+ }
+
+ // Build image list
+
+ // This is SAFE: the binaries themselves are unmodified.
+
+ std::vector<LayoutInfo> addressSortedDylibs = objcDylibs;
+ std::sort(addressSortedDylibs.begin(), addressSortedDylibs.end(), ByAddressSorter());
+
+ uint64_t hinfoVMAddr = optRWSection->addr() + optRWSection->size() - optRWRemaining;
+ HeaderInfoOptimizer<A> hinfoOptimizer;
+ err = hinfoOptimizer.init(objcDylibs.size(), optRWData, optRWRemaining);
+ if (err) {
+ warn(archName(), err);
+ return;
+ }
+ for(typename std::vector<LayoutInfo>::const_iterator it = addressSortedDylibs.begin(); it != addressSortedDylibs.end(); ++it) {
+ const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ hinfoOptimizer.update(this, mh, pointersInData);
+ }
+
+
// Update selector references and build selector list
// This is SAFE: if we run out of room for the selector table,
// Heuristic: choose selectors from libraries with more cstring data first.
// This tries to localize selector cstring memory.
ObjCSelectorUniquer<A> uniq(this);
- std::vector<LayoutInfo> sortedDylibs = fDylibs;
- std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
+ std::vector<LayoutInfo> sizeSortedDylibs = objcDylibs;
+ std::sort(sizeSortedDylibs.begin(), sizeSortedDylibs.end(), ByCStringSectionSizeSorter());
SelectorOptimizer<A, ObjCSelectorUniquer<A> > selOptimizer(uniq);
- for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
+ for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
selOptimizer.optimize(this, mh);
}
- if ( verbose ) {
- fprintf(stderr, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq.strings().size());
+ uint64_t seloptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
+ objc_opt::objc_selopt_t *selopt = new(optROData) objc_opt::objc_selopt_t;
+ err = selopt->write(seloptVMAddr, optRORemaining, uniq.strings());
+ if (err) {
+ warn(archName(), err);
+ return;
}
+ optROData += selopt->size();
+ optRORemaining -= selopt->size();
+ selopt->byteswap(E::little_endian), selopt = NULL;
- // Write selector table in read-only data.
- size_t selTableOffset = P::round_up(headerSize);
- size_t selTableSize;
- objc_opt::objc_selopt_t *seloptData = (objc_opt::objc_selopt_t *)
- mappedAddressForVMAddress(optROSection->addr() + selTableOffset);
- err = objc_opt::write_selopt(seloptData,
- optROSection->addr() + selTableOffset,
- optROSection->size() - selTableOffset,
- uniq.strings(),
- E::little_endian, &selTableSize);
+
+ // Build class table.
+
+ // This is SAFE: the binaries themselves are unmodified.
+
+ ClassListBuilder<A> classes(hinfoOptimizer);
+ ClassWalker< A, ClassListBuilder<A> > classWalker(classes);
+ for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+ const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ classWalker.walk(this, mh);
+ }
+
+ uint64_t clsoptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
+ objc_opt::objc_clsopt_t *clsopt = new(optROData) objc_opt::objc_clsopt_t;
+ err = clsopt->write(clsoptVMAddr, optRORemaining,
+ classes.classNames(), classes.classes(), verbose);
if (err) {
warn(archName(), err);
return;
}
+ optROData += clsopt->size();
+ optRORemaining -= clsopt->size();
+ size_t duplicateCount = clsopt->duplicateCount();
+ clsopt->byteswap(E::little_endian), clsopt = NULL;
+
+
+ // Sort method lists.
+
+ // This is SAFE: modified binaries are still usable as unsorted lists.
+ // This must be done AFTER uniquing selectors.
+
+ MethodListSorter<A> methodSorter;
+ for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+ macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ methodSorter.optimize(this, mh);
+ }
+
+
+ // Repair ivar offsets.
+
+ // This is SAFE: the runtime always validates ivar offsets at runtime.
+
+ IvarOffsetOptimizer<A> ivarOffsetOptimizer;
+ for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+ const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ ivarOffsetOptimizer.optimize(this, mh);
+ }
+
+
+ // Success. Mark dylibs as optimized.
+ for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
+ const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+ const macho_section<P> *imageInfoSection;
+ imageInfoSection = mh->getSection("__DATA", "__objc_imageinfo");
+ if (!imageInfoSection) {
+ imageInfoSection = mh->getSection("__OBJC", "__image_info");
+ }
+ if (imageInfoSection) {
+ objc_image_info<A> *info = (objc_image_info<A> *)
+ mappedAddressForVMAddress(imageInfoSection->addr());
+ info->setOptimizedByDyld();
+ }
+ }
+
+
+ // Success. Update RO header last.
+ E::set32(optROHeader->selopt_offset, seloptVMAddr - optROSection->addr());
+ E::set32(optROHeader->clsopt_offset, clsoptVMAddr - optROSection->addr());
+ E::set32(optROHeader->headeropt_offset, hinfoVMAddr - optROSection->addr());
if ( verbose ) {
- size_t totalSize = headerSize + selTableSize;
+ size_t roSize = optROSection->size() - optRORemaining;
+ size_t rwSize = optRWSection->size() - optRWRemaining;
fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
"(%d%%) used in libobjc read-only optimization section\n",
- archName(), totalSize, optROSection->size(),
- (int)(totalSize / (double)optROSection->size() * 100));
+ archName(), roSize, optROSection->size(),
+ percent(roSize, optROSection->size()));
+ fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
+ "(%d%%) used in libobjc read/write optimization section\n",
+ archName(), rwSize, optRWSection->size(),
+ percent(rwSize, optRWSection->size()));
+ fprintf(stderr, "update_dyld_shared_cache: for %s, "
+ "uniqued %zu selectors\n",
+ archName(), uniq.strings().size());
fprintf(stderr, "update_dyld_shared_cache: for %s, "
"updated %zu selector references\n",
archName(), uniq.count());
+ fprintf(stderr, "update_dyld_shared_cache: for %s, "
+ "updated %zu ivar offsets\n",
+ archName(), ivarOffsetOptimizer.optimized());
+ fprintf(stderr, "update_dyld_shared_cache: for %s, "
+ "sorted %zu method lists\n",
+ archName(), methodSorter.optimized());
+ fprintf(stderr, "update_dyld_shared_cache: for %s, "
+ "recorded %zu classes (%zu duplicates)\n",
+ archName(), classes.classNames().size(), duplicateCount);
fprintf(stderr, "update_dyld_shared_cache: for %s, "
"wrote objc metadata optimization version %d\n",
archName(), objc_opt::VERSION);
}
- // if r/w section exists in libojc attempt to optimize categories into classes
- if ( optRWSection != NULL ) {
- // Attach categories to classes in the same framework.
- // Build aggregated (but unsorted) method lists in read-write data.
-
- // This is SAFE: if we run out of room while attaching categories in
- // a binary then previously-edited binaries are still valid. (This assumes
- // each binary is processed all-or-nothing, which CategoryAttacher does.)
- // This must be done AFTER uniquing selectors.
- // This must be done BEFORE sorting method lists.
-
- size_t categoryOffset = 0;
- uint8_t *categoryData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr() + categoryOffset);
- CategoryAttacher<A> categoryAttacher(categoryData, optRWSection->size() - categoryOffset);
- for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
- macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
- err = categoryAttacher.optimize(this, mh, pointersInData);
- if (err) {
- warn(archName(), err);
- return;
- }
- }
- size_t categorySize = categoryAttacher.bytesUsed();
-
-
- // Sort method lists.
-
- // This is SAFE: modified binaries are still usable as unsorted lists.
- // This must be done AFTER uniquing selectors.
- // This must be done AFTER attaching categories.
-
- MethodListSorter<A> methodSorter;
- for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
- macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
- methodSorter.optimize(this, mh);
- }
-
- if ( verbose ) {
- size_t totalRWSize = categorySize;
- fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
- "(%d%%) used in libobjc read-write optimization section\n",
- archName(), totalRWSize, optRWSection->size(),
- (int)(totalRWSize / (double)optRWSection->size() * 100));
- fprintf(stderr, "update_dyld_shared_cache: for %s, "
- "attached %zu categories (%zd bytes used)\n",
- archName(), categoryAttacher.count(),
- categoryAttacher.bytesUsed());
- }
- }
-
- // Success. Update RO header last
- E::set32(optROHeader->selopt_offset, headerSize);
-
return;
}
template <> bool SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
template <> bool SharedCache<arm>::addCacheSlideInfo() { return true; }
template <> bool SharedCache<x86>::addCacheSlideInfo() { return false; }
-template <> bool SharedCache<ppc>::addCacheSlideInfo() { return false; }
template <typename A>
-bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
+bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
int archCount, bool keepSignatures)
{
bool didUpdate = false;
throwf("file modified during cache creation: %s", path);
if ( verbose )
- fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getID().name);
+ fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getFilePath());
try {
const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
for (int i=0; i < segs.size(); ++i) {
// 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 ) {
}
// 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);
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,
-static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
+static void setSharedDylibs(const char* rootPath, const char* overlayPath, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
{
// set file system root
- ArchGraph::setFileSystemRoot(rootPath, usesOverlay);
+ ArchGraph::setFileSystemRoot(rootPath);
+ ArchGraph::setFileSystemOverlay(overlayPath);
// initialize all architectures requested
for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
}
-static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
+static void scanForSharedDylibs(const char* rootPath, const char* overlayPath, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
{
char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
- // in -overlay mode, still look for roots in /var/db/dyld
// in -root mode, look for roots in /rootpath/var/db/dyld
- if ( !usesOverlay && (strlen(rootPath) != 0) ) {
+ if ( rootPath[0] != '\0' ) {
strcpy(rootDirOfPathFiles, rootPath);
strcat(rootDirOfPathFiles, dirOfPathFiles);
dirOfPathFiles = rootDirOfPathFiles;
if ( rootsPaths.size() == 0 )
fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
- setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
+ setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
}
-static void setSharedDylibs(const char* rootPath, bool usesOverlay, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
+static void setSharedDylibs(const char* rootPath, const char* overlayPath, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
{
std::vector<const char*> rootsPaths;
parsePathsFile(pathsFile, rootsPaths);
- setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
+ setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
}
-static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const char* cacheDir, const std::set<ArchPair>& onlyArchs,
+static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs,
bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures)
{
bool didUpdate = false;
else
fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
switch ( a->arch ) {
- case CPU_TYPE_POWERPC:
- {
- #if __i386__ || __x86_64__
- // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
- SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
- didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
- #else
- SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
- didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
- #endif
- }
- break;
case CPU_TYPE_I386:
{
- SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
- didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+ didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
}
break;
case CPU_TYPE_X86_64:
{
- SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
- didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+ didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
}
break;
case CPU_TYPE_ARM:
{
- SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
- didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+ didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
}
break;
}
{
std::set<ArchPair> onlyArchs;
const char* rootPath = "";
+ const char* overlayPath = "";
const char* dylibListFile = NULL;
bool force = false;
bool alphaSort = false;
bool optimize = true;
- bool hasRoot = false;
- bool hasOverlay = false;
bool verify = false;
bool keepSignatures = false;
+ bool explicitCacheDir = false;
const char* cacheDir = NULL;
try {
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));
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));
}
}
}
- // 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];
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 ) {
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));
// 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) {
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),
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);
ImageLoader::~ImageLoader()
{
+ if ( fRealPath != NULL )
+ delete [] fRealPath;
if ( fPathOwnedByImage && (fPath != NULL) )
delete [] fPath;
if ( fDynamicReferences != NULL ) {
strcpy((char*)fPath, path);
fPathOwnedByImage = true; // delete fPath when this image is destructed
fPathHash = hash(fPath);
+ fRealPath = NULL;
}
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)
{
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);
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);
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;
}
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 );
depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib);
}
// check found library version is compatible
- if ( actualInfo.minVersion < requiredLibInfo.info.minVersion ) {
+ // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version
+ if ( (requiredLibInfo.info.minVersion != 0xFFFFFFFF) && (actualInfo.minVersion < requiredLibInfo.info.minVersion) ) {
// record values for possible use by CrashReporter or Finder
dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
(*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;
// 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;
// initialize this image
bool hasInitializers = this->doInitialization(context);
- // let anyone know we finished initalizing this image
+ // <rdar://problem/10491874> initialize any upward depedencies
+ if ( hasUpwards ) {
+ for(unsigned int i=0; i < libraryCount(); ++i) {
+ ImageLoader* dependentImage = libImage(i);
+ // <rdar://problem/10643239> ObjC CG hang
+ // only init upward lib here if lib is not downwardly referenced somewhere
+ if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) {
+ dependentImage->recursiveInitialization(context, this_thread, timingInfo);
+ }
+ }
+ }
+
+ // let anyone know we finished initializing this image
fState = dyld_image_state_initialized;
oldState = fState;
context.notifySingle(dyld_image_state_initialized, this);
#elif __x86_64__
#define SHARED_REGION_BASE SHARED_REGION_BASE_X86_64
#define SHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64
-#elif __ppc__
- #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC
- #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC
-#elif __ppc64__
- #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC64
- #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC64
#elif __arm__
#define SHARED_REGION_BASE SHARED_REGION_BASE_ARM
#define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
#endif
+#ifndef LC_MAIN
+ #define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */
+ struct entry_point_command {
+ uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
+ uint32_t cmdsize; /* 24 */
+ uint64_t entryoff; /* file (__TEXT) offset of main() */
+ uint64_t stacksize;/* if not zero, initial stack size */
+ };
+#endif
#define SPLIT_SEG_SHARED_REGION_SUPPORT __arm__
-#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define PREBOUND_IMAGE_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__ || __arm__)
-#define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
+#define SPLIT_SEG_DYLIB_SUPPORT (__i386__ || __arm__)
+#define PREBOUND_IMAGE_SUPPORT (__i386__ || __arm__)
+#define TEXT_RELOC_SUPPORT (__i386__ || __arm__)
+#define DYLD_SHARED_CACHE_SUPPORT (__i386__ || __x86_64__ || __arm__)
+#define SUPPORT_OLD_CRT_INITIALIZATION (__i386__)
#define SUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__)
#define SUPPORT_VERSIONED_PATHS (__i386__ || __x86_64__)
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#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
void (*removeImage)(ImageLoader* image);
void (*registerDOFs)(const std::vector<DOFInfo>& dofs);
void (*clearAllDepths)();
+ void (*printAllDepths)();
unsigned int (*imageCount)();
void (*setNewProgramVars)(const ProgramVars&);
bool (*inSharedCache)(const char* path);
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;
// st_mtime from stat() on file
time_t lastModified() const;
- // only valid for main executables, returns a pointer its entry point
+ // only valid for main executables, returns a pointer its entry point from LC_UNIXTHREAD
+ virtual void* getThreadPC() const = 0;
+
+ // only valid for main executables, returns a pointer its main from LC_<MAIN
virtual void* getMain() const = 0;
// dyld API's require each image to have an associated mach_header
bool neverUnload() const { return fNeverUnload; }
void setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
+
+ bool isReferencedDownward() { return fIsReferencedDownward; }
+ bool isReferencedUpward() { return fIsReferencedUpward; }
+
// triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
static void printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo);
// used instead of directly deleting image
static void deleteImage(ImageLoader*);
- void setPath(const char* path); // only called for images created from memory
+ void setPath(const char* path);
+ void setPaths(const char* path, const char* realPath);
void setPathUnowned(const char* path);
void clearDepth() { fDepth = 0; }
+ int getDepth() { return fDepth; }
void setBeingRemoved() { fBeingRemoved = true; }
bool isBeingRemoved() const { return fBeingRemoved; }
static uint64_t fgTotalInitTime;
static std::vector<InterposeTuple> fgInterposingTuples;
const char* fPath;
+ const char* fRealPath;
dev_t fDevice;
ino_t fInode;
time_t fLastModified;
fBeingRemoved : 1,
fAddFuncNotified : 1,
fPathOwnedByImage : 1,
+ fIsReferencedDownward : 1,
+ fIsReferencedUpward : 1,
fWeakSymbolsBound : 1;
static uint16_t fgLoadOrdinal;
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);
*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:
*compressed = true;
break;
case LC_SEGMENT_COMMAND:
+ segCmd = (struct macho_segment_command*)cmd;
// ignore zero-sized segments
- if ( ((struct macho_segment_command*)cmd)->vmsize != 0 )
+ if ( segCmd->vmsize != 0 )
*segCount += 1;
+#if CODESIGNING_SUPPORT
+ // <rdar://problem/7942521> all load commands must be in an executable segment
+ if ( (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) {
+ if ( (segCmd->fileoff != 0) || (segCmd->filesize < (mh->sizeofcmds+sizeof(macho_header))) )
+ dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
+ if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
+ dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
+ foundLoadCommandSegment = true;
+ }
+#endif
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
}
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);
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)];
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);
void ImageLoaderMachO::registerInterposing()
{
// mach-o files advertise interposing by having a __DATA __interpose section
- uintptr_t textStart = this->segActualLoadAddress(0);
- uintptr_t textEnd = this->segActualEndAddress(0);
- // <rdar://problem/8268602> verify that the first segment load command is for a read-only segment
- if ( ! fGoodFirstSegment )
- return;
struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
tuple.replacementImage = this;
tuple.replacee = interposeArray[i].replacee;
// <rdar://problem/7937695> verify that replacement is in this image
- if ( (tuple.replacement >= textStart) && (tuple.replacement < textEnd) ) {
+ if ( this->containsAddress((void*)tuple.replacement) ) {
for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
if ( it->replacee == tuple.replacee ) {
tuple.replacee = it->replacement;
}
}
+void* ImageLoaderMachO::getThreadPC() const
+{
+ const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+ const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+ const struct load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd == LC_MAIN ) {
+ entry_point_command* mainCmd = (entry_point_command*)cmd;
+ void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData);
+ // <rdar://problem/8543820&9228031> verify entry point is in image
+ if ( this->containsAddress(entry) )
+ return entry;
+ else
+ throw "LC_MAIN entryoff is out of range";
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+ return NULL;
+}
+
void* ImageLoaderMachO::getMain() const
{
switch (cmd->cmd) {
case LC_UNIXTHREAD:
{
- #if __ppc__
- const ppc_thread_state_t* registers = (ppc_thread_state_t*)(((char*)cmd) + 16);
- return (void*)(registers->srr0 + fSlide);
- #elif __ppc64__
- const ppc_thread_state64_t* registers = (ppc_thread_state64_t*)(((char*)cmd) + 16);
- return (void*)(registers->srr0 + fSlide);
- #elif __i386__
+ #if __i386__
const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
- return (void*)(registers->eip + fSlide);
+ void* entry = (void*)(registers->eip + fSlide);
#elif __x86_64__
const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
- return (void*)(registers->rip + fSlide);
+ void* entry = (void*)(registers->rip + fSlide);
#elif __arm__
const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16);
- return (void*)(registers->__pc + fSlide);
+ void* entry = (void*)(registers->__pc + fSlide);
#else
#warning need processor specific code
#endif
+ // <rdar://problem/8543820&9228031> verify entry point is in image
+ if ( this->containsAddress(entry) ) {
+ return entry;
+ }
}
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
- return NULL;
+ throw "no valid entry point";
}
bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
#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
const uint32_t cmd_count = mh->ncmds;
const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
const struct load_command* cmd;
- // set up __dyld section
- // optimizations:
- // 1) do nothing if image is in dyld shared cache and dyld loaded at same address as when cache built
- // 2) first read __dyld value, if already correct don't write, this prevents dirtying a page
- if ( !fInSharedCache || !context.dyldLoadedAtSameAddressNeededBySharedCache ) {
+ // There used to be some optimizations to skip this section scan, but we need to handle the
+ // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
+ // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
+ if ( true ) {
cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
#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
void ImageLoaderMachO::doImageInit(const LinkContext& context)
{
if ( fHasDashInit ) {
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // <rdar://problem/8543820> verify initializers are in first segment for dylibs
- if ( this->isDylib() && !fGoodFirstSegment ) {
- if ( context.verboseInit )
- dyld::log("dyld: ignoring -init in %s\n", this->getPath());
- return;
- }
- uintptr_t textStart = this->segActualLoadAddress(0);
- uintptr_t textEnd = this->segActualEndAddress(0);
-#endif
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
const struct load_command* cmd = cmds;
switch (cmd->cmd) {
case LC_ROUTINES_COMMAND:
Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // <rdar://problem/8543820> verify initializers are in first segment for dylibs
- if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
- if ( context.verboseInit )
- dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
- }
- else {
-#endif
- if ( context.verboseInit )
- dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
- func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
+ // <rdar://problem/8543820&9228031> verify initializers are in image
+ if ( ! this->containsAddress((void*)func) ) {
+ dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
}
-#endif
+ if ( context.verboseInit )
+ dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
+ func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
{
if ( fHasInitializers ) {
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // <rdar://problem/8543820> verify initializers are in first segment for dylibs
- if ( this->isDylib() && !fGoodFirstSegment ) {
- if ( context.verboseInit )
- dyld::log("dyld: ignoring all initializers in %s\n", this->getPath());
- return;
- }
- uintptr_t textStart = this->segActualLoadAddress(0);
- uintptr_t textEnd = this->segActualEndAddress(0);
-#endif
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
const struct load_command* cmd = cmds;
const uint32_t count = sect->size / sizeof(uintptr_t);
for (uint32_t i=0; i < count; ++i) {
Initializer func = inits[i];
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // <rdar://problem/8543820> verify initializers are in first segment for dylibs
- if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
- if ( context.verboseInit )
- dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
+ // <rdar://problem/8543820&9228031> verify initializers are in image
+ if ( ! this->containsAddress((void*)func) ) {
+ dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
}
- else {
-#endif
- if ( context.verboseInit )
- dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
- func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- }
-#endif
+ if ( context.verboseInit )
+ dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
+ func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
}
}
}
const uint32_t count = sect->size / sizeof(uintptr_t);
for (uint32_t i=count; i > 0; --i) {
Terminator func = terms[i-1];
+ // <rdar://problem/8543820&9228031> verify terminators are in image
+ if ( ! this->containsAddress((void*)func) ) {
+ dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath());
+ }
if ( context.verboseInit )
dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
func();
intptr_t slide = this->assignSegmentAddresses(context);
if ( context.verboseMapping )
dyld::log("dyld: Mapping %s\n", this->getPath());
- // <rdar://problem/8268602> verify that the first segment load command is for a r-x segment
- // that starts at begining of file and is larger than all load commands
- uintptr_t firstSegMappedStart = segPreferredLoadAddress(0) + slide;
- uintptr_t firstSegMappedEnd = firstSegMappedStart + this->segSize(0);
- if ( (this->segLoadCommand(0)->initprot == (VM_PROT_EXECUTE|VM_PROT_READ))
- && (this->segFileOffset(0) == 0)
- && (this->segFileSize(0) != 0)
- && (this->segSize(0) > ((macho_header*)fMachOData)->sizeofcmds) ) {
- fGoodFirstSegment = true;
- }
// map in all segments
for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
vm_size_t size = segFileSize(i);
uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
- // <rdar://problem/8268602> verify other segments map after first
- if ( (i != 0) && (requestedLoadAddress < firstSegMappedEnd) )
- fGoodFirstSegment = false;
int protection = 0;
if ( !segUnaccessible(i) ) {
// If has text-relocs, don't set x-bit initially.
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;
fHasDashInit : 1,
fHasInitializers : 1,
fHasTerminators : 1,
- fGoodFirstSegment : 1,
fRegisteredAsRequiresCoalescing : 1; // <rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
#include <libkern/OSAtomic.h>
#include <libkern/OSCacheControl.h>
-#if __ppc__ || __ppc64__
- #include <mach-o/ppc/reloc.h>
-#endif
#if __x86_64__
#include <mach-o/x86_64/reloc.h>
#endif
#include "ImageLoaderMachOClassic.h"
#include "mach-o/dyld_images.h"
-// optimize strcmp for ppc
-#if __ppc__
- #include <ppc_intrinsics.h>
-#else
- #define astrcmp(a,b) strcmp(a,b)
-#endif
-
-
// in dyldStartup.s
extern "C" void fast_stub_binding_helper_interface();
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);
}
}
-#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)
{
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;
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);
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 ) {
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";
}
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;
noteAccessedLinkEditAddress(pivot);
noteAccessedLinkEditAddress(pivotStr);
#endif
- int cmp = astrcmp(key, pivotStr);
+ int cmp = strcmp(key, pivotStr);
if ( cmp == 0 )
return pivot;
if ( cmp > 0 ) {
noteAccessedLinkEditAddress(pivot);
noteAccessedLinkEditAddress(pivotStr);
#endif
- int cmp = astrcmp(key, pivotStr);
+ int cmp = strcmp(key, pivotStr);
if ( cmp == 0 )
return pivot;
if ( cmp > 0 ) {
{
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__
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
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);
}
// remember this is from shared cache and cannot be unloaded
image->fInSharedCache = true;
- image->fGoodFirstSegment = true;
image->setNeverUnload();
image->setSlide(slide);
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) {
if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR ) {
if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
// this node has a stub and resolver, run the resolver to get target address
- read_uleb128(exportNode, exportTrieEnd); // skip over stub
+ uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData; // skip over stub
+ // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
+ for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+ // replace all references to 'replacee' with 'replacement'
+ if ( stub == it->replacee ) {
+ if ( context.verboseInterposing ) {
+ dyld::log("dyld interposing: lazy replace 0x%lX with 0x%lX from %s\n",
+ it->replacee, it->replacement, this->getPath());
+ }
+ return it->replacement;
+ }
+ }
typedef uintptr_t (*ResolverProc)(void);
ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
uintptr_t result = (*resolver)();
#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
-// 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__
// 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;
//
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;
#endif
static ImageLoader* sMainExecutable = NULL;
static bool sProcessIsRestricted = false;
+static RestrictedReason sRestrictedReason = restrictedNot;
static unsigned int sInsertedDylibCount = 0;
static std::vector<ImageLoader*> sAllImages;
static std::vector<ImageLoader*> sImageRoots;
//#define ALTERNATIVE_LOGFILE "/dev/console"
+
static int sLogfile = STDERR_FILENO;
#if LOG_BINDINGS
}
-// forward declaration
-#if __ppc__ || __i386__
-bool isRosetta();
-#endif
-
-
static void registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
{
-#if __ppc__
- // can't dtrace a program running emulated under rosetta rdar://problem/5179640
- if ( isRosetta() )
- return;
-#endif
const unsigned int dofSectionCount = dofs.size();
if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
if ( handlers != NULL ) {
dyld_image_info info;
info.imageLoadAddress = image->machHeader();
- info.imageFilePath = image->getPath();
+ info.imageFilePath = image->getRealPath();
info.imageFileModDate = image->lastModified();
for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
const char* result = (*it)(state, 1, &info);
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;
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 )
(*it)->clearDepth();
}
+static void printAllDepths()
+{
+ for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
+ dyld::log("%03d %s\n", (*it)->getDepth(), (*it)->getShortName());
+}
+
+
static unsigned int imageCount()
{
return sAllImages.size();
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);
closedir(dirp);
}
}
+#endif // SUPPORT_VERSIONED_PATHS
+
//
// Turns a colon separated list of strings into a NULL terminated array
}
}
*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 ) {
#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;
//
-#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 },
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) {
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 ) {
// 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
{
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);
// see if this image in the cache was already loaded via a different path
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
ImageLoader* anImage = *it;
- if ( anImage->machHeader() == mhInCache )
+ if ( (const macho_header*)anImage->machHeader() == mhInCache )
return anImage;
}
// do nothing if not already loaded and if RTLD_NOLOAD
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;
-
#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__
#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"
#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;
}
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);
}
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);
}
// 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
// add to list of handlers
std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
if ( handlers != NULL ) {
- handlers->push_back(handler);
+ // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
+ // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
+ if ( state == dyld_image_state_mapped )
+ handlers->insert(handlers->begin(), handler);
+ else
+ handlers->push_back(handler);
// call callback with all existing images
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
ImageLoader* image = *it;
dyld_image_info info;
info.imageLoadAddress = image->machHeader();
- info.imageFilePath = image->getPath();
+ info.imageFilePath = image->getRealPath();
info.imageFileModDate = image->lastModified();
// should only call handler if state == image->state
if ( image->getState() == state )
gLinkContext.removeImage = &removeImage;
gLinkContext.registerDOFs = ®isterDOFs;
gLinkContext.clearAllDepths = &clearAllDepths;
+ gLinkContext.printAllDepths = &printAllDepths;
gLinkContext.imageCount = &imageCount;
gLinkContext.setNewProgramVars = &setNewProgramVars;
#if DYLD_SHARED_CACHE_SUPPORT
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
return false;
}
-
+#if SUPPORT_VERSIONED_PATHS
//
// Peeks at a dylib file and returns its current_version and install_name.
// Returns false on error.
return false;
}
-
+#endif // SUPPORT_VERSIONED_PATHS
+
#if 0
static void printAllImages()
{
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
ImageLoader* image = *it;
if ( (image->referenceCount() == 0) && !image->neverUnload() && !image->isBeingRemoved() ) {
+ if ( image->isReferencedUpward() ) {
+ // temp hack for rdar://problem/10973109
+ // if an image is upwardly referenced, we really need to scan all images
+ // to see if any are still using it.
+ continue;
+ }
try {
- //dyld::log("garbageCollectImages: deleting %s\n", image->getPath());
+ //dyld::log("garbageCollectImages: deleting %p %s\n", image, image->getPath());
image->setBeingRemoved();
removeImage(image);
ImageLoader::deleteImage(image);
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;
CS_OPS_STATUS,
&flags,
sizeof(flags)) != -1) {
- if (flags & CS_RESTRICT)
- return true;
+ if (flags & CS_RESTRICT) {
+ sRestrictedReason = restrictedByEntitlements;
+ return true;
+ }
}
#endif
return false;
}
+
+
+// <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
+static void addDyldImageToUUIDList()
+{
+ const struct macho_header* mh = (macho_header*)&__dso_handle;
+ const uint32_t cmd_count = mh->ncmds;
+ const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
+ const struct load_command* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd) {
+ case LC_UUID: {
+ uuid_command* uc = (uuid_command*)cmd;
+ dyld_uuid_info info;
+ info.imageLoadAddress = (mach_header*)mh;
+ memcpy(info.imageUUID, uc->uuid, 16);
+ addNonSharedCacheImageUUID(info);
+ return;
+ }
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+}
+
+
+
//
// Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
// sets up some registers and call this function.
// 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);
// 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];
sExecPath = s;
}
}
- uintptr_t result = 0;
sMainExecutableMachHeader = mainExecutableMH;
sProcessIsRestricted = processRestricted(mainExecutableMH);
if ( sProcessIsRestricted ) {
#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);
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
#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();
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();
// 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.
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;
}
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);
}
dyld_all_image_infos.systemOrderFlag = 0;
}
-
-
typedef void (*MonitorProc)(char *lowpc, char *highpc);
static void monInitCallback(ImageLoader* image, void* userData)
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
}
// 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
// magic "search what I would see" handle
if ( handle == RTLD_NEXT ) {
-#if __ppc__
- // <rdar://problem/7628929> work around for llvmgcc bug
- void* fa = __builtin_frame_address(0);
- fa = *(void**)fa;
- fa = *(void**)fa;
- void* callerAddress = *((void**)(((int)fa)+8));
-#else
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
-#endif
ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
if ( sym != NULL ) {
ImageLoader* image = dyld::findImageContainingAddress(address);
if ( image != NULL )
- return image->getPath();
+ return image->getRealPath();
return NULL;
}
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
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
}
#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,
&pthread_key_create, &pthread_setspecific,
&malloc_size,
&pthread_getspecific,
- &__cxa_finalize};
+ &__cxa_finalize,
+ &start};
//
/* -*- 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@
*
-#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 {
}
}
-#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__
};
-//
-// 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;
#include <mach-o/loader.h>
#include <mach-o/ldsyms.h>
#include <mach-o/reloc.h>
-#if __ppc__ || __ppc64__
- #include <mach-o/ppc/reloc.h>
-#endif
#if __x86_64__
#include <mach-o/x86_64/reloc.h>
#endif
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";
}
-extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp
extern "C" void mach_init();
//
// 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
_pthread_keys_init();
#endif
- // enable C++ exceptions to work inside dyld
- dyld_exceptions_init(dyldsMachHeader, slide);
-
// allow dyld to use mach messaging
mach_init();
// 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);
}
*/
#include <Availability.h>
+#include <stddef.h>
//
// This is the temporary private interface between libSystem.B.dylib and dyld
//
+
+int NXArgc = 0;
+const char** NXArgv = NULL;
+const char** environ = NULL;
+const char* __progname = NULL;
+
+
+
//
// Long ago, the compiler driver added -ldylib1.o to every dylib which caused a
// __DATA,__dyld section to be added every dylib. The new LINKEDIT format no longer requires
// to some sort of vtable based interface, libdyld still needs a __DATA,__dyld section.
// The code below adds that section.
//
-struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
+struct __DATA__dyld {
+ long lazy;
+ int (*lookup)(const char*, void**);
+ // ProgramVars
+ const void* mh;
+ int* NXArgcPtr;
+ const char*** NXArgvPtr;
+ const char*** environPtr;
+ const char** __prognamePtr;
+};
-static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, 0 };
+static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld")))
+ = { 0, 0, NULL, &NXArgc, &NXArgv, &environ, &__progname };
#if __arm__ && __MAC_OS_X_VERSION_MIN_REQUIRED
// <rdar://problem/8755380>
}
-
-
void* (*pthread_getspecific)(pthread_key_t);
// added in version 8
void (*cxa_finalize)(const void*);
+ // added in version 9
+ void* startGlueToCallExit;
};
#if __cplusplus
};
/*
- * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @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.
*
.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
.align 2,0x90
.globl __dyld_start
__dyld_start:
+ popq %rdi # param1 = mh of app
pushq $0 # push a zero for debugger end of frames marker
movq %rsp,%rbp # pointer to base of kernel frame
andq $-16,%rsp # force SSE alignment
+ subq $16,%rsp # room for local variables
- # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
- movq 8(%rbp),%rdi # param1 = mh into %rdi
- movl 16(%rbp),%esi # param2 = argc into %esi
- leaq 24(%rbp),%rdx # param3 = &argv[0] into %rdx
+ # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh, &startGlue)
+ movl 8(%rbp),%esi # param2 = argc into %esi
+ leaq 16(%rbp),%rdx # param3 = &argv[0] into %rdx
movq __dyld_start_static(%rip), %r8
leaq __dyld_start(%rip), %rcx
subq %r8, %rcx # param4 = slide into %rcx
leaq ___dso_handle(%rip),%r8 # param5 = dyldsMachHeader
- call __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_
+ leaq -8(%rbp),%r9
+ call __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_Pm
+ movq -8(%rbp),%rdi
+ cmpq $0,%rdi
+ jne Lnew
- # clean up stack and jump to result
+ # clean up stack and jump to "start" in main executable
movq %rbp,%rsp # restore the unaligned stack pointer
- addq $16,%rsp # remove the mh argument, and debugger end frame marker
+ addq $8,%rsp # remove the mh argument, and debugger end frame marker
movq $0,%rbp # restore ebp back to zero
jmp *%rax # jump to the entry point
+ # LC_MAIN case, set up stack for call to main()
+Lnew: addq $16,%rsp # remove local variables
+ pushq %rdi # simulate return address into _start in libdyld
+ movq 8(%rbp),%rdi # main param1 = argc into %rdi
+ leaq 16(%rbp),%rsi # main param2 = &argv[0] into %rsi
+ leaq 0x8(%rsi,%rdi,8),%rdx # main param3 = &env[0] into %rdx
+ movq %rdx,%rcx
+Lapple: movq (%rcx),%r8
+ add $8,%rcx
+ testq %r8,%r8 # look for NULL ending env[] array
+ jne Lapple # main param4 = apple into %rcx
+ jmp *%rax # jump to main(argc,argv,env,apple) with return address set to _start
+
#endif /* __x86_64__ */
-#if __ppc__ || __ppc64__
-#include <architecture/ppc/mode_independent_asm.h>
-
- .data
- .align 2
-__dyld_start_static_picbase:
- .g_long L__dyld_start_picbase
-Lmh: .g_long ___dso_handle
-
-#if __ppc__
- .set L_mh_offset,0
- .set L_argc_offset,4
- .set L_argv_offset,8
-#else
- .set L_mh_offset,0
- .set L_argc_offset,8 ; stack is 8-byte aligned and there is a 4-byte hole between argc and argv
- .set L_argv_offset,16
-#endif
-
- .text
- .align 2
-; stable entry points into dyld
- .globl _stub_binding_helper
-_stub_binding_helper:
- b _stub_binding_helper_interface
- nop
- .globl _dyld_func_lookup
-_dyld_func_lookup:
- b __Z18lookupDyldFunctionPKcPm
- nop
-_offset_to_dyld_all_image_infos:
- .long _dyld_all_image_infos - . + 0x1010
- .long 0
- # space for future stable entry points
- .space 16
-
-
- .text
- .align 2
-__dyld_start:
- mr r26,r1 ; save original stack pointer into r26
- subi r1,r1,GPR_BYTES ; make space for linkage
- clrrgi r1,r1,5 ; align to 32 bytes
- addi r0,0,0 ; load 0 into r0
- stg r0,0(r1) ; terminate initial stack frame
- stgu r1,-SF_MINSIZE(r1); allocate minimal stack frame
-
- # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
- lg r3,L_mh_offset(r26) ; r3 = mach_header
- lwz r4,L_argc_offset(r26) ; r4 = argc (int == 4 bytes)
- addi r5,r26,L_argv_offset ; r5 = argv
- bcl 20,31,L__dyld_start_picbase
-L__dyld_start_picbase:
- mflr r31 ; put address of L__dyld_start_picbase in r31
- addis r6,r31,ha16(__dyld_start_static_picbase-L__dyld_start_picbase)
- lg r6,lo16(__dyld_start_static_picbase-L__dyld_start_picbase)(r6)
- subf r6,r6,r31 ; r6 = slide
- addis r7,r31,ha16(Lmh-L__dyld_start_picbase)
- lg r7,lo16(Lmh-L__dyld_start_picbase)(r7)
- add r7,r6,r7 ; r7 = dyld_mh
- bl __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_
-
- ; clean up stack and jump to result
- mtctr r3 ; Put entry point in count register
- mr r12,r3 ; also put in r12 for ABI convention.
- addi r1,r26,GPR_BYTES; Restore the stack pointer and remove the
- ; mach_header argument.
- bctr ; jump to the program's entry point
-
- .globl dyld_stub_binding_helper
-dyld_stub_binding_helper:
- trap
-L_end:
-#endif /* __ppc__ */
#if __arm__
+ .syntax unified
.data
.align 2
__dyld_start_static_picbase:
.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:
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:
.align 2
.globl _dyld_fatal_error
_dyld_fatal_error:
-#if __ppc__ || __ppc64__ || __arm__
+#if __arm__
trap
nop
#elif __x86_64__ || __i386__
int dummy_dyld_symbol = 1;
-#include <stdlib.h>
-
-// The following API's are deprecated.
-// In Mac OS X 10.4 we only do a minimal implementation of these API's
-// to keep from breaking existing clients (Omni and MS Crash Reporters).
-//
-// This minmal implementation only allows inspection of one process and
-// only reveals the current images in that process (no notification of
-// later image changes). It assumes both processes use the same dyld
-// and dyld has not slid in either process.
-//
-#if __ppc__
-
-#include "mach-o/dyld_debug.h"
-#include "mach-o/dyld_gdb.h"
-#include "mach-o/dyld_priv.h"
-
-// global state set up by _dyld_debug_subscribe_to_events() and accessed by _dyld_debug_module_name()
-static const struct dyld_image_info* sImages = NULL;
-static uint32_t sImagesCount = 0;
-static task_port_t sImagesTaskPort = 0;
-
-
-// reads an address range out of another process
-// returns a malloc'ed block that caller should free
-static void* xprocess_read(task_port_t target_task, const void* address, size_t len)
-{
- void* result = NULL;
- mach_vm_address_t page_address = (uint32_t)address & (-4096);
- mach_vm_address_t last_page_address = ((uint32_t)address + len + 4095) & (-4096);
- mach_vm_size_t page_size = last_page_address - page_address;
- uint8_t* local_start;
- uint32_t local_len;
- kern_return_t r = vm_read(
- target_task,
- page_address,
- page_size,
- (vm_offset_t*)&local_start,
- &local_len);
- if ( r == KERN_SUCCESS ) {
- result = malloc(len);
- if ( result != NULL )
- memcpy(result, &local_start[(uint32_t)address - page_address], len);
- vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_len);
- }
- return result;
-}
-
-// reads a c-string out of another process. The returned string should be vm_deallocated.
-// All strings must be less than 1 to 2 pages long
-static const char* xprocess_read_string(task_port_t target_task, const void* address)
-{
- char* result = NULL;
- mach_vm_address_t page_address = (uint32_t)address & (-4096);
- mach_vm_size_t page_size = 0x2000; // always read two pages
- uint8_t* local_start;
- uint32_t local_len;
- kern_return_t r = vm_read(
- target_task,
- page_address,
- page_size,
- (vm_offset_t*)&local_start,
- &local_len);
- if ( r == KERN_SUCCESS ) {
- const char* str = (char*)&local_start[(uint32_t)address - page_address];
- return str;
- }
- return result;
-}
-
-
-// SPI into dyld to get address of _dyld_get_all_image_infos data structure
-static const struct dyld_all_image_infos* dyld_get_all_image_infos()
-{
- static const struct dyld_all_image_infos* (*p)() = NULL;
-
- if ( p == NULL )
- _dyld_func_lookup("__dyld_get_all_image_infos", (void**)&p);
-
- if ( p != NULL )
- return p();
- else
- return NULL;
-}
-
-
-
-/*
- * _dyld_debug_module_name() is passed a dyld_debug_module struct and
- * sets image_name and module_name as well as the nameCnts. If the module
- * does not refer to a valid module DYLD_INVALID_ARGUMENTS is returned.
- */
-enum dyld_debug_return
-_dyld_debug_module_name(
-task_port_t target_task,
-unsigned long send_timeout,
-unsigned long rcv_timeout,
-boolean_t inconsistent_data_ok,
-struct dyld_debug_module module,
-char **image_name,
-unsigned long *image_nameCnt,
-char **module_name,
-unsigned long *module_nameCnt)
-{
- // examine sImage* info set up by _dyld_debug_subscribe_to_events()
- if ( sImagesTaskPort == target_task ) {
- unsigned int i;
- for (i=0; i < sImagesCount; ++i) {
- if ( module.header == sImages[i].imageLoadAddress ) {
- // copy requested string
- const char* path = xprocess_read_string(sImagesTaskPort, sImages[i].imageFilePath);
- if ( path != NULL ) {
- *image_name = (char*)path;
- *image_nameCnt = strlen(path);
- *module_name = NULL;
- *module_nameCnt = 0;
- return DYLD_SUCCESS;
- }
- }
- }
- }
-
- // not supported
- return DYLD_INVALID_ARGUMENTS;
-}
-
-
-/*
- * set_dyld_debug_error_func() is called to register a function to be called
- * when error occurs in the dyld debug API's.
- */
-void
-_dyld_debug_set_error_func(
-void (*func)(struct dyld_debug_error_data *e))
-{
- // do nothing
-}
-
-
-
-// Examine a mach_header in another process and determine its slide
-static ptrdiff_t slideForHeader(task_port_t target_task, const struct mach_header* otherAddressHeader)
-{
- ptrdiff_t result = 0;
- const struct mach_header* mh = xprocess_read(target_task, otherAddressHeader, 0x2000);
- if ( mh != NULL ) {
- int i;
- const struct segment_command *sgp =
- (const struct segment_command *)((char*)mh + sizeof(mh));
-
- for (i = 0; i < mh->ncmds; i++){
- if (sgp->cmd == LC_SEGMENT) {
- if (sgp->fileoff == 0 && sgp->filesize != 0) {
- result = (uintptr_t)mh - (uintptr_t)sgp->vmaddr;
- break;
- }
- }
- sgp = (const struct segment_command *)((char *)sgp + sgp->cmdsize);
- }
- free((void*)mh);
- }
- return result;
-}
-
-
-/*
- * _dyld_debug_subscribe_to_events creates a new thread that is will call the
- * specified dyld_event_routine when dynamic link events occur in the target
- * task. This uses _dyld_debug_add_event_subscriber() and is just a different
- * interface to get events.
- */
-enum dyld_debug_return
-_dyld_debug_subscribe_to_events(
-task_port_t target_task,
-unsigned long send_timeout,
-unsigned long rcv_timeout,
-boolean_t inconsistent_data_ok,
-void (*dyld_event_routine)(struct dyld_event event))
-{
- sImages = NULL;
- sImagesCount = 0;
- sImagesTaskPort = 0;
- // get location of dyld_get_all_image_infos in this process
- // It is possible that dyld slid in one of the processes, in which case this fails
- const struct dyld_all_image_infos* infoOtherAddressSpace = dyld_get_all_image_infos();
- if ( infoOtherAddressSpace != NULL ) {
- const struct dyld_all_image_infos* infos;
- infos = (const struct dyld_all_image_infos*)xprocess_read(target_task, infoOtherAddressSpace, sizeof(struct dyld_all_image_infos));
- if ( infos != NULL ) {
- // sanity check version
- if ( infos->version == 1 ) {
- sImages = xprocess_read(target_task, infos->infoArray, infos->infoArrayCount * sizeof(struct dyld_image_info));
- if ( sImages != NULL ) {
- int i;
- // save info info into sImage* globals for use by later calls to _dyld_debug_module_name()
- sImagesCount = infos->infoArrayCount;
- sImagesTaskPort = target_task;
- // tell caller about every image
- for (i=0; i < infos->infoArrayCount; ++i) {
- struct dyld_event addEvent;
- bzero(&addEvent, sizeof(struct dyld_event));
- const struct mach_header* mh = sImages[i].imageLoadAddress;
- addEvent.type = DYLD_IMAGE_ADDED;
- addEvent.arg[0].header = (struct mach_header*)mh;
- addEvent.arg[0].vmaddr_slide = slideForHeader(target_task, mh);
- addEvent.arg[0].module_index = 0;
- (*dyld_event_routine)(addEvent);
- }
- }
- }
- // we free the dyld_all_image_infos struct, but not the array we copied
- // The array is left in sImage* for use by later calls to _dyld_debug_module_name()
- free((void*)infos);
- }
- }
-
- // tell client event handler no more images
- struct dyld_event event;
- event.type = DYLD_PAST_EVENTS_END;
- (*dyld_event_routine)(event);
-
- return DYLD_SUCCESS;
-}
-
-#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
// _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;
{
_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;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#ifdef __i386__
+
+ .align 2
+ .globl _start
+ .private_extern _start
+start:
+ nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+ movl %eax,(%esp) # pass result from main() to exit()
+ call _exit
+ hlt
+
+#endif /* __i386__ */
+
+
+#if __x86_64__
+
+ .align 2
+ .globl _start
+ .private_extern _start
+start:
+ nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+ movl %eax,%edi # pass result from main() to exit()
+ call _exit
+ hlt
+
+#endif
+
+
+#if __arm__
+
+ .align 2
+ .globl _start
+ .private_extern _start
+start:
+ nop // <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+_start:
+ bl _exit // result in r0 already in param reg r0
+ trap
+
+#endif /* __arm__ */
+
#endif
-#if __ppc__ || __ppc64__
-#include <architecture/ppc/mode_independent_asm.h>
-/*
- * This is the interface for the stub_binding_helper for the ppc:
- * The caller has placed in r11 the address of the a lazy pointer to be filled
- * in with the value for the defined symbol and placed in r12 the address of
- * the the mach header this pointer comes from.
- *
- * r11 address of lazy pointer
- * r12 address of mach header
- */
-#define LRSAVE MODE_CHOICE(8,16)
-#define STACK_SIZE MODE_CHOICE(144,288)
-#define R3SAVE MODE_CHOICE(56,112)
-#define R4SAVE MODE_CHOICE(60,120)
-#define R5SAVE MODE_CHOICE(64,128)
-#define R6SAVE MODE_CHOICE(68,136)
-#define R7SAVE MODE_CHOICE(72,144)
-#define R8SAVE MODE_CHOICE(76,152)
-#define R9SAVE MODE_CHOICE(80,160)
-#define R10SAVE MODE_CHOICE(84,168)
-
-
- .text
- .align 2
- .globl _stub_binding_helper_interface
-_stub_binding_helper_interface:
- mflr r0 ; get link register value
- stg r0,LRSAVE(r1) ; save link register value in the linkage area
- stgu r1,-STACK_SIZE(r1) ; save stack pointer and update it
-
- stg r3,R3SAVE(r1) ; save all registers that could contain
- stg r4,R4SAVE(r1) ; parameters to the routine that is being
- stg r5,R5SAVE(r1) ; bound.
- stg r6,R6SAVE(r1)
- stg r7,R7SAVE(r1)
- stg r8,R8SAVE(r1)
- stg r9,R9SAVE(r1)
- stg r10,R10SAVE(r1)
-
- mr r3,r12 ; move address of mach header to 1st parameter
- mr r4,r11 ; move address of lazy pointer to 2nd parameter
- ; call dyld::bindLazySymbol(mh, lazy_symbol_pointer_address)
- bl __ZN4dyld14bindLazySymbolEPK11mach_headerPm
- mr r12,r3 ; move the symbol`s address into r12
- mtctr r12 ; move the symbol`s address into count register
-
- lg r0,STACK_SIZE+LRSAVE(r1) ; get old link register value
-
- lg r3,R3SAVE(r1) ; restore all registers that could contain
- lg r4,R4SAVE(r1) ; parameters to the routine that was bound.
- lg r5,R5SAVE(r1)
- lg r6,R6SAVE(r1)
- lg r7,R7SAVE(r1)
- lg r8,R8SAVE(r1)
- lg r9,R9SAVE(r1)
- lg r10,R10SAVE(r1)
-
- addi r1,r1,STACK_SIZE; restore old stack pointer
- mtlr r0 ; restore link register
-
- bctr ; jump to the symbol`s address that was bound
-
-#endif /* __ppc__ */
-
#if __arm__
/*
* This is the interface for the stub_binding_helper for ARM:
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}
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
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 * * *"
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;
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
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;
}
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
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;
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;
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;
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()
{
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;
}
##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2011 Apple Inc. All rights reserved.
#
# @APPLE_LICENSE_HEADER_START@
#
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
${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
bool checkdata()
{
- return ( mydata[10] == 0 );
+ return ( mydata[9] == 0 );
}
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]
#
./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
}
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;
}
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:
.text
+ .align 2
.globl _mystart
_mystart:
#if __i386__
--- /dev/null
+##
+# Copyright (c) 2011 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+ ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib bar.c
+ ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbaz.dylib baz.c -Wl,-upward_library,libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib bar.c libbaz.dylib
+ ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.c libbar.dylib
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libbaz.dylib libbar.dylib libfoo.dylib
+
--- /dev/null
+
+int bar = 10;
--- /dev/null
+void baz() {}
--- /dev/null
+
+void foo() {}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h> // fprintf(), NULL
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_priv.h>
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int main(int argc, const char* argv[])
+{
+ if ( ! dlopen_preflight("libfoo.dylib") ) {
+ FAIL("dlopen_preflight-cycle libfoo.dylib should not be loadable");
+ return EXIT_SUCCESS;
+ }
+
+ void* handle = dlopen("libbar.dylib", RTLD_NOLOAD);
+ if ( handle != NULL ) {
+ FAIL("dlopen_preflight-cycle libbar.dylib was left loaded by dlopen_preflight()");
+ return EXIT_SUCCESS;
+ }
+
+ handle = dlopen("libbaz.dylib", RTLD_NOLOAD);
+ if ( handle != NULL ) {
+ FAIL("dlopen_preflight-cycle libbaz.dylib was left loaded by dlopen_preflight()");
+ return EXIT_SUCCESS;
+ }
+
+ handle = dlopen("libfoo.dylib", RTLD_NOLOAD);
+ if ( handle != NULL ) {
+ FAIL("dlopen_preflight-cycle libfoo.dylib was left loaded by dlopen_preflight()");
+ return EXIT_SUCCESS;
+ }
+
+ PASS("dlopen_preflight-cycle");
+ return EXIT_SUCCESS;
+}
+++ /dev/null
-##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
-#
-# @APPLE_LICENSE_HEADER_START@
-#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
-#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
-# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
-##
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-STACK_BASE = 0x8fe01000
-STACK_SIZE = 0x00100000
-
-ifeq "armv6" "$(ARCH)"
- STACK_BASE = 0x2fe01000
- STACK_SIZE = 0x00100000
-endif
-ifeq "armv7" "$(ARCH)"
- STACK_BASE = 0x2fe01000
- STACK_SIZE = 0x00100000
-endif
-ifeq "ppc64" "$(ARCH)"
- STACK_BASE = 0x7fff5ff00000
- STACK_SIZE = 0x00400000
-endif
-ifeq "x86_64" "$(ARCH)"
- STACK_BASE = 0x7fff5ff00000
- STACK_SIZE = 0x00400000
-endif
-
-
-
-all-check: all check
-
-check:
- ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main
-
-all:
- ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,${STACK_SIZE}
-
-clean:
- ${RM} ${RMFLAGS} main
+++ /dev/null
-/*
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-#include <stdlib.h> // EXIT_SUCCESS
-#include <dlfcn.h>
-#include <mach-o/dyld_priv.h>
-
-#include "test.h"
-
-//
-// This builds an executable that is just big enough to force dyld to slide a bit
-//
-#if __arm__
- #define ARRAY_SIZE 66582528
-#else
- #define ARRAY_SIZE 335400000
-#endif
-
-//int bigarray1[ARRAY_SIZE];
-
-int
-main()
-{
- // call a dyld function that will execute lots of code and bus error dyld was not slid
- dlsym(RTLD_DEFAULT, "foobar");
-
- return EXIT_SUCCESS;
-}
-
-
/// 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[])
{
--- /dev/null
+##
+# 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
+
--- /dev/null
+void bar() {}
--- /dev/null
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h> // fprintf(), NULL
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <mach-o/dyld_priv.h>
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "bar" in its name from loading.
+//
+
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+ //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+ if ( strstr(info[0].imageFilePath, "bar") != NULL )
+ return "can't load bar";
+ return NULL;
+}
+
+
+static void load(const char* name)
+{
+ void* handle = dlopen(name, RTLD_LAZY);
+ if ( handle != NULL ) {
+ FAIL("image-state-deny-all_image_infos: dlopen(%s) should have failed", name);
+ exit(0);
+ }
+}
+
+
+int main(int argc, const char* argv[])
+{
+ // tell dyld we want to know when images are mapped
+ dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+
+ const struct dyld_all_image_infos* infos = _dyld_get_all_image_infos();
+ const uint32_t initialCount = infos->infoArrayCount;
+
+ load("bar.bundle");
+
+ if ( infos->infoArrayCount != initialCount ){
+ FAIL("image-state-deny-all_image_infos: infoArrayCount should not have changed");
+ exit(0);
+ }
+
+ //for (int i=0; i < infos->infoArrayCount; ++i)
+ // printf("mh=%p, path=%s\n", infos->infoArray[i].imageLoadAddress, infos->infoArray[i].imageFilePath);
+
+ PASS("image-state-deny-all_image_infos");
+
+ return EXIT_SUCCESS;
+}
*/
#include <stdlib.h>
#include <mach-o/dyld.h>
+#include <dlfcn.h>
#include "test.h"
all-check: all check
check:
- ./main
+ ${PASS_IFF_FAILURE} ./main
all:
${CC} ${CCFLAGS} -I${TESTROOT}/include bar.c -dynamiclib -o libbar.dylib
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
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;
}
TESTROOT = ../..
include ${TESTROOT}/include/common.makefile
+SHELL = bash # use bash shell so we can redirect just stderr
+
PWD = `pwd`
ifeq "$(OS_NAME)" "iPhoneOS"
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
/*
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <string.h>
#include <dlfcn.h>
+#include <stdbool.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+extern bool allocationSeen(void* p);
+typedef bool (*seenProc)(void*);
int main()
{
- const char* x = strdup("123");
-
- if ( (strcmp(&x[-16], "hello") == 0) )
+ void* x = strdup("123");
+
+ seenProc seen = (seenProc)dlsym(RTLD_DEFAULT, "allocationSeen");
+
+ if ( (seen != NULL) && (*seen)(x) )
PASS("interpose-basic-shared-cache");
else
FAIL("interpose-basic-shared-cache");
/*
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
+#include <stdbool.h>
#include <mach-o/dyld-interposing.h>
+#include <malloc/malloc.h>
-// return blocks that have preceeding 16-bytes filled with "hello"
+static void* seenAllocations[128];
+static int seenAllocationIndex = 0;
+
+// record each malloc result in a ring buffer
void* my_malloc(size_t size)
{
- char* x = malloc(size+16);
- strcpy(x, "hello");
- return &x[16];
+ char* x = malloc(size);
+ seenAllocations[seenAllocationIndex++] = x;
+ seenAllocationIndex = (seenAllocationIndex & 127); //wrap around
+ return x;
}
DYLD_INTERPOSE(my_malloc, malloc)
+
+bool allocationSeen(void* p)
+{
+ for(int i=0; i < 127; ++i) {
+ if ( seenAllocations[i] == p )
+ return true;
+ }
+ return false;
+}
+
+
+
--- /dev/null
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+#
+# <rdar://problem/10879179> a dylib is found via symlink and must find another dylib relative to the symlink
+#
+
+all-check: all check
+
+check:
+ ./bin/main
+
+all:
+ mkdir -p Frameworks/Foo.framework/Versions/A
+ mkdir -p Frameworks/Bar.framework/Versions/A
+ ${CC} bar.c -dynamiclib -o Frameworks/Bar.framework/Versions/A/Bar -install_name @loader_path/../Bar.framework/Bar
+ (cd Frameworks/Foo.framework; ln -fs Versions/A/Foo)
+ (cd Frameworks/Bar.framework; ln -fs Versions/A/Bar)
+ ${CC} foo.c -dynamiclib -o Frameworks/Foo.framework/Versions/A/Foo -install_name @loader_path/../Frameworks/Foo.framework/Foo Frameworks/Bar.framework/Versions/A/Bar
+ mkdir -p bin
+ ${CC} -I${TESTROOT}/include main.c -o bin/main Frameworks/Foo.framework/Versions/A/Foo
+
+
+clean:
+ ${RM} -rf *~ Frameworks bin
--- /dev/null
+void bar()
+{
+}
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+ foo();
+ PASS("loader_path-symlink");
+ return EXIT_SUCCESS;
+}
EXTRA_OPTIONS =
endif
+ifeq "iPhoneOS" "$(OS_NAME)"
+ EXTRA_OPTIONS =
+endif
+
# run a PIE four times and verify its load address was different every time
--- /dev/null
+##
+# 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
--- /dev/null
+
+int bar(void)
+{
+ return 2;
+}
--- /dev/null
+int baz()
+{
+ return 3;
+}
+
--- /dev/null
+_baz
+_frob
--- /dev/null
+int foo(void)
+{
+ return 1;
+}
--- /dev/null
+_foo
+_bar
+_baz
+_frob
--- /dev/null
+int frob()
+{
+ return 4;
+}
+
--- /dev/null
+
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+extern int foo();
+extern int bar();
+extern int baz();
+extern int frob();
+
+int (*pfoo)() = &foo;
+int (*pbar)() = &bar;
+int (*pbaz)() = &baz;
+int (*pfrob)() = &frob;
+
+
+int main()
+{
+ if ( foo() != 1 )
+ FAIL("re-export-symbol-dylib: foo() returned wrong value");
+ else if ( bar() != 2 )
+ FAIL("re-export-symbol-dylib: bar() returned wrong value");
+ else if ( baz() != 3 )
+ FAIL("re-export-symbol-dylib: baz() returned wrong value");
+ else if ( frob() != 4 )
+ FAIL("re-export-symbol-dylib: frob() returned wrong value");
+
+ else if ( (*pfoo)() != 1 )
+ FAIL("re-export-symbol-dylib: (*pfoo)() returned wrong value");
+ else if ( (*pbar)() != 2 )
+ FAIL("re-export-symbol-dylib: (*pbar)() returned wrong value");
+ else if ( (*pbaz)() != 3 )
+ FAIL("re-export-symbol-dylib: (*pbaz)() returned wrong value");
+ else if ( (*pfrob)() != 4 )
+ FAIL("re-export-symbol-dylib: (*pfrob)() returned wrong value");
+ else
+ PASS("re-export-symbol-dylib");
+ return 0;
+}
+
# 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
#include <stdio.h> // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <unistd.h>
+#include <Availability.h>
#include <mach-o/getsect.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
extern void foo();
extern int fooData;
return EXIT_SUCCESS;
}
+#else
+
+int main()
+{
+ // iOS does not have modifiable stubs
+ PASS("read-only-stubs");
+ return EXIT_SUCCESS;
+}
+
+#endif
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
all-check: all check
check:
- ${RUN_AS_USER} $(PWD)/main-with-env
+ ${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
all: main
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
+#include <unistd.h>
#include <mach-o/dyld.h>
#include "test.h"
--- /dev/null
+##
+# 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
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+ foo();
+
+ // make sure foo's path does not have .. in it
+ int count = _dyld_image_count();
+ bool found = false;
+ for(int i=0; i < count; ++i) {
+ const char* name = _dyld_get_image_name(i);
+ if ( strstr(name, "libfoo.dylib") == 0 ) {
+ found = true;
+ if ( strstr(name, "..") != NULL ) {
+ FAIL("rpath-introspection: _dyld_get_image_name(%d) returned %s", i, name);
+ return EXIT_SUCCESS;
+ }
+ }
+ }
+ if ( !found ) {
+ FAIL("rpath-introspection: _dyld_get_image_name() never returned libfoo.dylib");
+ return EXIT_SUCCESS;
+ }
+
+ // make sure dladdr path does not have .. in it
+ Dl_info info;
+ if ( dladdr(&foo, &info) == 0 ) {
+ FAIL("rpath-introspection: dladdr() failed");
+ return EXIT_SUCCESS;
+ }
+ if ( strstr(info.dli_fname, "..") != NULL ) {
+ FAIL("rpath-introspection: dladdr() returned path with .. in it");
+ return EXIT_SUCCESS;
+ }
+
+ PASS("rpath-introspection");
+ return EXIT_SUCCESS;
+}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <dlfcn.h>
#include "test.h"
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
all-check: all check
check:
- ${RUN_AS_USER} $(PWD)/main-with-env
+ ${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
all: main
## 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
--- /dev/null
+##
+# 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
+
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+
+static int which_foo = 0;
+
+void set_foo(int x)
+{
+ which_foo = x;
+}
+
+static int foo_ten()
+{
+ return 10;
+}
+
+static int foo_zero()
+{
+ return 0;
+}
+
+
+// This foo is a "resolver" function that return the actual address of "foo"
+void* foo()
+{
+ __asm__(".symbol_resolver _foo"); // magic until we have compiler support
+ if ( which_foo == 0 )
+ return &foo_zero;
+ else
+ return &foo_ten;
+}
+
--- /dev/null
+
+extern int foo();
+extern void set_foo(int);
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include "foo.h"
+
+int main(int argc, const char* argv[])
+{
+ if ( getenv("DYLD_INSERT_LIBRARIES") == NULL ) {
+ if ( foo() != 0 ) {
+ FAIL("symbol-resolver-interposed: foo() != 0");
+ return EXIT_SUCCESS;
+ }
+ }
+ else {
+ if ( foo() != 20 ) {
+ FAIL("symbol-resolver-interposed: foo() != 20");
+ return EXIT_SUCCESS;
+ }
+ }
+
+ PASS("symbol-resolver-interposed");
+ return EXIT_SUCCESS;
+}
--- /dev/null
+
+#include <mach-o/dyld-interposing.h>
+#include "foo.h"
+
+int myfoo()
+{
+ return 20;
+}
+
+DYLD_INTERPOSE(myfoo, foo)
## 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
--- /dev/null
+##
+# 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
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern void* terminators[] __asm__("section$start$__DATA$__mod_term_func");
+
+
+__attribute__((destructor))
+void myterm()
+{
+ FAIL("terminator-bounds-check, terminator called");
+ exit(0);
+}
+
+
+
+int
+main()
+{
+ // stomp on terminator routine to point into libSystem (_rand)
+ terminators[0] = &rand;
+ return EXIT_SUCCESS;
+}
#include <stdio.h> // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <unistd.h>
+#include <Availability.h>
#include <mach-o/getsect.h>
#include <mach-o/ldsyms.h>
#include <mach/mach.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
static vm_prot_t getPermission(void* addr)
{
checkStubs(stubAddr);
}
+#else
+
+void foo()
+{
+ // iOS does not have text relocs
+}
+
+#endif
#include <stdio.h> // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <unistd.h>
+#include <Availability.h>
#include <mach-o/getsect.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+
extern void foo();
static vm_prot_t getPermission(void* addr)
return EXIT_SUCCESS;
}
+#else
+
+int main()
+{
+ // iOS does not have text relocs
+ PASS("text-relocs-perm");
+ return EXIT_SUCCESS;
+}
+
+#endif
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
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:
.text
+ .align 2
_junk: .space 1024*1024
## 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
- # _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
/*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
-extern int* get_a(); // initially 0
-extern int* get_b(); // initially 5
+__thread int a = 0; // initially 0
+__thread int b = 5; // initially 5
+// simulate C++ initializer on thread local variables
void myinit()
{
- *get_a() = 11;
- *get_b() = 42;
+ a = 11;
+ b = 42;
}
-
static void* work(void* arg)
{
//fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
- if ( *get_a() != 11 ) {
+ if ( a != 11 ) {
FAIL("tlv-initializer: get_a() not initialized to 11");
exit(0);
}
- if ( *get_b() != 42 ) {
+ if ( b != 42 ) {
FAIL("tlv-initializer: get_b() not initialized to 42");
exit(0);
}
## 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
--- /dev/null
+##
+# 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
+
+
+
--- /dev/null
+#include <stdio.h>
+#include "common.h"
+
+
+
+static __attribute__((constructor)) void myInit()
+{
+ setB();
+ //fprintf(stderr, "init b\n");
+}
--- /dev/null
+#include <stdio.h>
+
+
+
+static __attribute__((constructor)) void myInit()
+{
+ //fprintf(stderr, "init c\n");
+}
--- /dev/null
+#include "common.h"
+#include <stdio.h>
+
+static bool b = false;
+static bool u = false;
+static bool isOk = true;
+
+void setB()
+{
+ if ( u || b )
+ isOk = false;
+ b = true;
+}
+
+void setU()
+{
+ if ( u )
+ isOk = false;
+ u = true;
+}
+
+// return true iff
+// setB() was called, then setU()
+bool ok()
+{
+ //fprintf(stderr, "isOk=%d, u=%d, b=%d\n", isOk, u, b);
+ return isOk && u && b;
+}
+
--- /dev/null
+#include <stdbool.h>
+
+extern void setB();
+extern void setU();
+
+extern bool ok();
+
--- /dev/null
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "common.h"
+
+int main()
+{
+ if ( ok() )
+ PASS("upward-dylib-init-order");
+ else
+ FAIL("upward-dylib-init-order");
+
+ return EXIT_SUCCESS;
+}
+
+
--- /dev/null
+#include <stdio.h>
+#include "common.h"
+
+
+static __attribute__((constructor)) void myInit()
+{
+ setU();
+ //fprintf(stderr, "init u\n");
+}
+
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
${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:
return state;
}
-void other()
+int getdownsup()
{
- whatsup();
+ return whatsup();
}
\ No newline at end of file
extern int getdown();
+extern int getdownsup();
PASS("upward-dylib");
else
FAIL("upward-dylib");
+
return EXIT_SUCCESS;
}
--- /dev/null
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "up.h"
+#include "down.h"
+
+int main()
+{
+ if ( getdownsup() )
+ PASS("upward-dylib");
+ else
+ FAIL("upward-dylib");
+
+ return EXIT_SUCCESS;
+}
+
+