]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-133.3.tar.gz developer-tools-44 v133.3
authorApple <opensource@apple.com>
Wed, 1 Aug 2012 23:05:07 +0000 (23:05 +0000)
committerApple <opensource@apple.com>
Wed, 1 Aug 2012 23:05:07 +0000 (23:05 +0000)
114 files changed:
ChangeLog [deleted file]
compile_stubs [new file with mode: 0755]
doc/design/bindings.png [new file with mode: 0644]
doc/design/hello.png [new file with mode: 0644]
doc/design/linker.html [new file with mode: 0644]
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/abstraction/MachOTrie.hpp
src/create_configure [new file with mode: 0755]
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/InputFiles.h
src/ld/LinkEdit.hpp
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/OutputFile.h
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/Snapshot.cpp [new file with mode: 0644]
src/ld/Snapshot.h [new file with mode: 0644]
src/ld/SymbolTable.cpp
src/ld/SymbolTable.h
src/ld/code-sign-blobs/blob.cpp [new file with mode: 0644]
src/ld/code-sign-blobs/blob.h [new file with mode: 0644]
src/ld/code-sign-blobs/endian.h [new file with mode: 0644]
src/ld/code-sign-blobs/memutils.h [new file with mode: 0644]
src/ld/code-sign-blobs/superblob.h [new file with mode: 0644]
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/archive_file.cpp
src/ld/parsers/archive_file.h
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_dylib_file.h
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/macho_relocatable_file.h
src/ld/parsers/opaque_section_file.cpp
src/ld/parsers/opaque_section_file.h
src/ld/passes/branch_island.cpp
src/ld/passes/branch_shim.cpp
src/ld/passes/compact_unwind.cpp
src/ld/passes/dtrace_dof.cpp
src/ld/passes/objc.cpp
src/ld/passes/order.cpp
src/ld/passes/stubs/stub_arm.hpp
src/ld/passes/stubs/stub_x86_64.hpp
src/ld/passes/stubs/stubs.cpp
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
src/other/rebase.cpp
unit-tests/bin/make-recursive.pl
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/16-byte-alignment/Makefile
unit-tests/test-cases/archive-r-ObjC/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-r-ObjC/bar.c [new file with mode: 0644]
unit-tests/test-cases/archive-r-ObjC/baz.m [new file with mode: 0644]
unit-tests/test-cases/archive-r-ObjC/cat.m [new file with mode: 0644]
unit-tests/test-cases/archive-r-ObjC/foo.m [new file with mode: 0644]
unit-tests/test-cases/archive-r-ObjC/main.c [new file with mode: 0644]
unit-tests/test-cases/branch-islands/Makefile
unit-tests/test-cases/branch-islands/atomic_space.s [new file with mode: 0644]
unit-tests/test-cases/data-in-code/Makefile [new file with mode: 0644]
unit-tests/test-cases/data-in-code/main.c [new file with mode: 0644]
unit-tests/test-cases/data-in-code/test.s [new file with mode: 0644]
unit-tests/test-cases/duplicate_symbols/Makefile [new file with mode: 0644]
unit-tests/test-cases/duplicate_symbols/duplicates.c [new file with mode: 0644]
unit-tests/test-cases/duplicate_symbols/main_extern.c [new file with mode: 0644]
unit-tests/test-cases/duplicate_symbols/main_no_extern.c [new file with mode: 0644]
unit-tests/test-cases/dylib-main/Makefile [new file with mode: 0644]
unit-tests/test-cases/dylib-main/foo.c [new file with mode: 0644]
unit-tests/test-cases/dylib-main/main.c [new file with mode: 0644]
unit-tests/test-cases/force-weak/Makefile [new file with mode: 0644]
unit-tests/test-cases/force-weak/foo.c [new file with mode: 0644]
unit-tests/test-cases/force-weak/test.c [new file with mode: 0644]
unit-tests/test-cases/force-weak/weak.exp [new file with mode: 0644]
unit-tests/test-cases/install-name-override/Makefile [new file with mode: 0644]
unit-tests/test-cases/install-name-override/foo.c [new file with mode: 0644]
unit-tests/test-cases/install-name-override/main.c [new file with mode: 0644]
unit-tests/test-cases/llvm-integration/Makefile
unit-tests/test-cases/lto-dead_strip-inline-asm/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-inline-asm/bar.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-unused/Makefile
unit-tests/test-cases/lto-preload-pie/Makefile
unit-tests/test-cases/no-uuid/Makefile
unit-tests/test-cases/objc-category-archive/Makefile
unit-tests/test-cases/objc-category-archive/test2.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-debug-notes/Makefile
unit-tests/test-cases/objc-category-optimize-load/Makefile
unit-tests/test-cases/objc-category-optimize/Makefile
unit-tests/test-cases/objc-category-warning/Makefile
unit-tests/test-cases/order_file/Makefile
unit-tests/test-cases/pipelined-linking/Makefile [new file with mode: 0644]
unit-tests/test-cases/pipelined-linking/bar.c [new file with mode: 0644]
unit-tests/test-cases/pipelined-linking/cat.c [new file with mode: 0644]
unit-tests/test-cases/pipelined-linking/foo.c [new file with mode: 0644]
unit-tests/test-cases/static-executable-pie/Makefile [new file with mode: 0644]
unit-tests/test-cases/static-executable-pie/bad.c [new file with mode: 0644]
unit-tests/test-cases/static-executable-pie/test.c [new file with mode: 0644]
unit-tests/test-cases/tentative-and-archive-code/Makefile
unit-tests/test-cases/tlv-dead_strip/Makefile
unit-tests/test-cases/weak_import-undefined/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak_import-undefined/weak.c [new file with mode: 0644]
unit-tests/test-cases/weak_import3/Makefile [deleted file]
unit-tests/test-cases/weak_import3/comment.txt [deleted file]
unit-tests/test-cases/weak_import3/foo.c [deleted file]
unit-tests/test-cases/weak_import3/foo.h [deleted file]
unit-tests/test-cases/weak_import3/foo1.c [deleted file]
unit-tests/test-cases/weak_import3/main.c [deleted file]

diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644 (file)
index 0514d7f..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,1681 +0,0 @@
-
--------- tagged ld64-128.1
-
-2011-09-13    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/10111122> Enable dyld to be put into the dyld shared cache
-
-2011-09-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10100056> Fix "using ld_classic" warning for i386 kexts
-
-2011-09-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10052396> LTO many have eliminated need for some undefines
-
--------- tagged ld64-128
-
-2011-09-08    Nick Kledzik    <kledzik@apple.com>
-
-       Rework 8924157 fix to sort all sections
-
-2011-09-07    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10089743> ER: -current_version should allow 64-bit a.b.c.d.e tuple
-
-2011-09-06    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10038370> -mdynamic-no-pic broke with movw of weak thumb symbol
-
-2011-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10057157> Turn crash into a warning if __dso_handle is defined in user code
-       Added test case: unit-tests/test-cases/dso_handle
-
-2011-08-31    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6780050> Add -fatal_warnings
-
-2011-08-30    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8482298> Support .weak_def_can_be_hidden via LTO interface
-
-2011-08-29    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/10043807> improve performance of zerofill->data ordering
-
-2011-08-29    Nick Kledzik    <kledzik@apple.com>
-
-       Implement -print_statistics
-
-2011-08-25    Nick Kledzik    <kledzik@apple.com>
-
-       check for overlaps between pinned segments and regular segments
-
-2011-08-23    Nick Kledzik    <kledzik@apple.com>
-
-       do got elimination more aggressively in static and preload mode
-
-2011-08-22    Nick Kledzik    <kledzik@apple.com>
-
-       enable __dso_handle in -preload
-
-2011-08-22    Nick Kledzik    <kledzik@apple.com>
-
-       fix section$end to sort to end of __mod_init_func section
-
-2011-08-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9737570> __constructor section removed with -dead_strip
-
-2011-08-11    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8828975> remove ld support for PowerPC
-
-2011-08-11    Nick Kledzik    <kledzik@apple.com>
-
-       Fix spurious -segaddr alignment warning
-
--------- tagged ld64-127.3
-
-2011-08-31    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8924157> [regression] C++ Initializers from archives not sorted
-       Added test case: unit-tests/test-cases/archive-init-order
-
--------- tagged ld64-127.2
-
-2011-08-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9945513> suppress version load command for simulator builds
-
--------- tagged ld64-127.1
-
-2011-07-26    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9847280> Csu needs to support for armv7 variants
-
--------- tagged ld64-127
-
-2011-07-26    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9838090> crash with TLS + -dead_strip
-
-2011-07-20    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9778727> ld64-123.2.1/ChangeLog contains internal train names and radar titles
-
-2011-07-17    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9777977> ld crashes with an assertion failure when linking WebKit with LTO
-       
-2011-07-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9779759> Personalities missing when using compact unwind
-
-2011-07-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9740166> force loaded archives not listed in LD_TRACE
-
-2011-07-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9716724> spurious warning: Codegen prevents image from working in dyld shared cache
-
-2011-07-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9707126> Fix -classic_linker option
-
--------- tagged ld64-126.5
-
-2011-06-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9618702> ld64-124.6: ld -r introduces duplicate symbols
-       
-2011-06-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9610466> loosen check for 32-bit absolute address out of range 
-               
--------- tagged ld64-126.3.1
-
-2011-06-15    Nick Kledzik    <kledzik@apple.com>
-
-       Update armv7 variants
-
--------- tagged ld64-126.2
-
-2011-06-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9461567> iOS ld -r loses dont-dead-strip attribute on __objc_nlclslist section
-
-2011-06-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9231829> LC_ENCRYPTION_INFO size can be wrong
-       
-
--------- tagged ld64-126.1
-
-2011-06-10    Nick Kledzik    <kledzik@apple.com>
-
-       Add back support for armv7 variants
-
--------- tagged ld64-126
-
-2011-06-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9581690> -ObjC does not work for simulator
-       
-2011-06-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9551362> clang ld: bad codegen, pointer diff
-       Added test case: unit-tests/test-cases/weak-def-hidden-and-global
-
-2011-06-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9553065> warning then assertion when libSystem.dylib is missing
-
-2011-06-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9544194> ld crash with resolver functions
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7259423> define way for compilers to specify compact unwind info
-       Added test case: unit-tests/test-cases/compact-unwind-basic
-       Updated unwinddump tool to display compact unwind info in .o files
-       
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       Allow 8612550 (turn ordered zero fill symbols into zero data) to work not just for dyld
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       Remove trailing /. in dwarf source dirs to cannoicalize paths
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       Sort debug notes by output order instead of input order.
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9537755> remove support for invoking ld_classic in iOS
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       Fix arm branch interworking in -r for armv6
-
-2011-06-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9521882> i386 regression with pointer-diff of same pointer
-
-2011-05-27    Nick Kledzik    <kledzik@apple.com>
-
-       Canonicalize dwarf source file dirname to always end in / 
-
-2011-05-27    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9513487> support arm branch interworking in -r mode (use extern relocs)
-
-2011-05-27    Nick Kledzik    <kledzik@apple.com>
-
-       Add -page_align_data_atoms option
-
-2011-05-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9292295> align(16384) doesn't produce 16K aligned globals on ARMv7
-
-2011-05-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9493908> support arm shims in sections other than __text
-
-2011-05-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8750693> ld64 should only install to the platform in iOS
-
-2011-05-19    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9452006> Ld assertion with unusual section order
-
-2011-05-17    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9441273> Linker is not automatically weak loading dylibs when all references are weak
-
--------- tagged ld64-125.3
-
-2011-05-12    Nick Kledzik    <kledzik@apple.com>
-
-       Fix missing split-seg-info for kindSetTargetImageOffset
-
-2011-05-12    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9420745> Linker crashes with __gcc_except_tab data belonging to no FDE
-
-2011-05-11    Nick Kledzik    <kledzik@apple.com>
-
-       Fix nop padding for arm code
-
-2011-05-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9394006> x86_64: cmp of GOT slot loses weak_import bit
-
--------- tagged ld64-125.2
-
-2011-05-02    Nick Kledzik    <kledzik@apple.com>
-
-       Fix -flat_namespace issue with not all indirect dylibs being processed
-
-2011-04-29    Nick Kledzik    <kledzik@apple.com>
-
-       Fix sign extention on i386 addends of extern vanilla relocs 
-
-2011-04-29    Nick Kledzik    <kledzik@apple.com>
-
-       Don't let -ObjC double load any archive members
-
-2011-04-29    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9356572> better warning about unaligned ARM functions
-
--------- tagged ld64-125.1
-
-2011-04-28    Nick Kledzik    <kledzik@apple.com>
-
-       Fix sign extention on arm sect-diff relocs so as to not trip rangeCheckAbsolute32() 
-
--------- tagged ld64-125
-
-2011-04-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8866673> the entry point should start out initially undefined
-
-2011-04-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
-
-2011-04-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6978069> ld adds undefined symbol from .exp file to kext bundle 
-
-2011-04-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7664544> Linker typo suggestions should ignore l- and L- symbols
-
-2011-04-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7952137> -order_file_statistics warns about syms in multiple .o files even when names in order file are prefixed
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
-       Add test case: unit-tests/test-cases/objc-category-warning
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7890410> don't let function from archive override a tentative definition
-       Add test case: unit-tests/test-cases/tentative-and-archive-code
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8822887> x86_64 -- lossy relocation at static link time (push/mov $imm)
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8989530> Add comment to error message when __ZTV symbols are undefined
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8995535> obsolete -no_compact_linkedit
-
-2011-04-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9281002> sect->sectname() passed to "%s" formats
-
-2011-04-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9275707> linking a sub library of libSystem should not warn about common symbols
-
-2011-04-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9282815> support movw/movt in static executables
-
-2011-04-12    Nick Kledzik    <kledzik@apple.com>
-
-       Rework ARM subtype handling to be table driven
-
-2011-04-11    Nick Kledzik    <kledzik@apple.com>
-
-       Error if -init or -e function not in image being linked
-
-2011-04-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9216420> -static and -stack_addr don't work together
-
-2011-03-31    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9183821> ld assert in LTO mode if libLTO suppresses a weak symbol it should have perserved
-
--------- tagged ld64-124.1
-
-2011-03-30    Nick Kledzik    <kledzik@apple.com>
-
-       log warning if ld_classic is invoked
-
-2011-03-30    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9209135> Support "-arch arm -force_cpusubtype_ALL" to keep gcc building
-
--------- tagged ld64-124
-
-2011-03-24    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/9144456> make libgcc_s and libSystem work for any link order
-       
-2011-03-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8750693> ld64 should only install to the platform in iOS trains
-
-2011-03-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9127471> ld64 should build stand-alone and not need libunwind headers
-
-2011-03-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9139782> add LC_VERSION_MIN_IPHONEOS to iOS targets, warn on mismatches
-
-2011-03-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8836481> Make iOS simulator a real platform with command line versioning
-
-2011-03-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8964869> static executables don't get function start information
-
-2011-03-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9112113> allow_sub_type_mismatches linker flag broken
-
-2011-03-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9106345> Add option to support merging zero fill sections
-       Add test case: unit-tests/test-cases/merge_zero_fill_sections
-
-2011-03-15    Nick Kledzik    <kledzik@apple.com>
-
-       Improve error message about text-relocs caused by direct access to global weak symbols.
-
-2011-03-10    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9116044> ld assert linking armv7 kext bundle on b/bl to external function
-
--------- tagged ld64-123.10
-
-2011-03-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9085618> linking x86_64 causes assert from changes in ld64-123.9
-
--------- tagged ld64-123.9
-
-2011-03-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9055754> movw/movt don't work in dyld shared cache
-
-2011-03-03    Nick Kledzik    <kledzik@apple.com>
-    
-    <rdar://problem/8995525> classic linkedit does not match compact for non-lazy pointers
-
-2011-02-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/9052679> Support armv7 variants
-
--------- tagged ld64-123.8
-
-2011-02-10    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8926992> Switch arm32 kexts to MH_KEXT_BUNDLE
-
--------- tagged ld64-123.7
-
-2011-02-10    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8926992> Switch arm32 kexts to MH_KEXT_BUNDLE, if LD_KEXT_BUNDLE is set
-
-2011-01-28    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8931747> spurious 'found branch-22 without store' warning
-
--------- tagged ld64-123.6
-
-2011-01-26    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8904405> crash with arm hi16/lo16 to external symbols
-
--------- tagged ld64-123.5
-
-2011-01-24    Nick Kledzik    <kledzik@apple.com>
-    
-    <rdar://problem/8910802> dyld synthesized tail call stubs don't always work
-
--------- tagged ld64-123.4
-
-2011-01-19    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8866345> __text with >10 alignment should disable close-stub optimization 
-
-2011-01-18    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8877072> :upper16: / :lower16: not working when targeting thumb functions
-
--------- tagged ld64-123.3
-
-2010-12-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8764917> ld64 making shims when not necessary
-
-2010-12-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8760268> Add work around for latest llvm-c/lto.h 
-
--------- tagged ld64-123.2.1
-
-2011-03-07    Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/8955206> enable i386 ASLR
-
--------- tagged ld64-123.2
-
-2010-12-10    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8746980> Man page typo: "dysmutil" under object_path_lto
-
-2010-12-10    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/8746896> ld64 crashes when warning about re-exported symbol
-
--------- tagged ld64-123.1
-
-2010-12-07    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8732097> assertion if symbol from re-exported dylib is in -exported_symbols_list
-
--------- tagged ld64-123
-
-2010-12-06    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8649182> Change default search order and add -search_dylibs_first to restore old behavior
-
-2010-12-06    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8626058> ld should consistently warn when resolvers are not exported
-
-2010-12-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8723307> data segment has file offset 0
-
--------- tagged ld64-122
-
-2010-12-01    Nick Kledzik    <kledzik@apple.com>
-
-       Add #define ARM_RELOC_HALF in case trying to build with old mach-o/arm/reloc.h header
-
-2010-11-30    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8134559> Linker should synthesize interworking stubs for tail calls
-       added test case: unit-tests/test-cases/branch-interworking
-
-2010-11-30    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8708091> Link Time Optimization error with tentative defs and -dead_strip
-       added test case: unit-tests/test-cases/lto-dead_strip-tentative
-
--------- tagged ld64-121
-
-2010-11-10    Nick Kledzik    <kledzik@apple.com>
-
-       Add -dylibs option to dyldinfo tool
-
-2010-11-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7441442> Need support for ARM/thumb upper/lower 16 bit relocation
-
-2010-11-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8624334> Spelling typo in linker warning 
-
-2010-11-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8616906> Xcode 4: ld -r doesn't work on files compiled with llvm-gcc -flto
-
-2010-11-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8618747> ld wrongly complaining about tlv relocs for i386
-
-2010-11-01    Nick Kledzik    <kledzik@apple.com>
-
-       Fix -why_live to list all references, not just first
-
-2010-11-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8612861> iOS is missing dof sections for armv7 slice
-
--------- tagged ld64-120.3
-
-2010-11-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8644314> revert default search order 
-       
--------- tagged ld64-120.2
-
-2010-11-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8510696> ld -r corrupts multiple non-lazy sections
-
--------- tagged ld64-120.1
-
-2010-10-25    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zero data
-
--------- tagged ld64-120
-
-2010-10-25    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8592564> ld should use this-image ordinal for symbols from re-exported non-public dylibs
-       added test case: unit-tests/test-cases/re-export-and-use
-
-2010-10-25    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
-
-2010-10-25    Nick Kledzik    <kledzik@apple.com>
-
-       Always print arch name on undefined symbols error
-       
-2010-10-25    Nick Kledzik    <kledzik@apple.com>
-
-       Add ld64 version number to crash logs
-       
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7952947> -objc_abi_version 1 not supported
-
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
-
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3560832> Change default search order and add -search_dylibs_first to restore old behavior
-
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6955037> -L flag should support a space between it and its argument
-
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8553647> Hidden resolver functions don't work with DYLD_BIND_AT_LAUNCH
-
-2010-10-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8541707> Support resolver functions for function pointer use from same linkage unit
-
-2010-10-19    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8571323> section$start$ does not always point to start of built in section types
-
--------- tagged ld64-119.2
-
-2010-10-18    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8553312> make having an ObjC2 class symbol in an export list be a warning instead of an error
-
-2010-10-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8553283> lazily produce (crt1.o missing) error
-
--------- tagged ld64-119.1
-
-2010-10-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8527740> ld -r can produce output with LC_DYLD_INFO load command
-
-2010-10-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8516692> ld doesn't pass stabs debug info through to the final executable any longer
-
-2010-10-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4251267> __UNIXSTACK placed incorrectly when -stack_addr < 0x4000000
-
-2010-10-05    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8267015> ld mishandles -lazy-l option
-       Updated test case: unit-tests/test-cases/lazy-dylib
-       
-2010-10-04    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8468240> -no_compact_unwind should suppress dwarf->CUE warnings
-
--------- tagged ld64-119
-
-2010-10-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6599016> use ld64 to link iBoot
-
-2010-10-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8504770> crash when entrypoint is thumb
-
-2010-10-01    Nick Kledzik    <kledzik@apple.com>
-
-       If -ios_version_min is used with -arch i386, assume simulator
-
-2010-10-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8500061> crash with multiple re-exported dylibs with same install_name
-
-2010-09-28    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8032130> Linker complains about resolver functions when architecture is inferred.
-       
-2010-09-28    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6751424> ARM subtype not set on LTO programs
-
-2010-09-28    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8481987> Link-Time Optimization assertion 
-       Added test cases: 
-               unit-tests/test-cases/lto-dead_strip-objc
-               unit-tests/test-cases/lto-dead_strip-some-hidden
-
-2010-09-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8441087> Support -dyld_env NAME=value
-
-2010-09-23    Nick Kledzik    <kledzik@apple.com>
-
-       Previous BranchIsland code changes to make buildable with clang++ were bad.  Fix.
-
-2010-09-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8274443> ld64 objc category merging asserts on category from old framework
-
-2010-09-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8469063> ASLR Sidebuild: Many Projects Fail checksyms_read_only_relocs Verifier
-
-2010-09-22    Nick Kledzik    <kledzik@apple.com>
-
-       Fix DOF section name bug
-
-2010-09-22    Nick Kledzik    <kledzik@apple.com>
-
-       Fixes to build with clang++
-
-2010-09-21    Nick Kledzik    <kledzik@apple.com>
-
-       In Resolver::fillInHelpersInInternalState(), dyld never needs stubs
-
-2010-09-21    Ivan Krstic     <ike@apple.com>
-
-       <rdar://problem/8457083> ld: support non-executable heap Mach-O header flag
-
-2010-09-21    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8175282> Xcode 4 linker fails with "address not in any section"
-
-2010-09-20    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8198832> assertion failure reading i386 yasm .o (not using scattered reloc)
-
-2010-09-20    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8430751> ld crashes when parsing dwarf and all code is not in __text
-
-2010-09-17    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8396450> magic segment symbol names don't work with preload executables
-       Update test case: unit-tests/test-cases/segment-labels
-
-2010-09-17    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8445985> OSO in DebugNotes for LTO should point to generated mach-o not, bitcode .o file
-
-2010-09-16    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8413931> FUN in debug map not rebased
-       Update test case: unit-tests/test-cases/rebase-basic
-
-2010-09-16    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8427133> Relocation failure with i386 32-bit diff to stub
-
-2010-09-16    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8437287> assert when targeting 10.5 and crt1.o/dylib1.o is not supplied
-
--------- tagged ld64-118.1
-
-2010-09-15    Nick Kledzik    <kledzik@apple.com>
-
-       Fix missing rebase commands that broke perl
-
-2010-09-15    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8252819> assert when .objc_class_name_* symbol missing
-       Add test case: unit-tests/test-cases/archive-ObjC-unexported
-
-2010-09-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8419850> linker does not honor $ld$hide for umbrella libraries
-       Added test case: unit-tests/test-cases/symbol-hiding-umbrella
-
-2010-09-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
-
-2010-09-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4942948> support -bind_at_load
-
-2010-09-07    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7989734> ld mis-handling std::tr1::anonymous symbols
-       Remove support for ordering gcc-4.0 compiled anonymous namespace symbols
-
-
--------- tagged ld64-118
-
-2010-09-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8308697> -preload should not have LINKEDIT segment
-       Added test case: unit-tests/test-cases/efi-basic
-
-2010-09-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8389578> trivial Objective-C app fails when using libLTO
-       Added test case: unit-tests/test-cases/lto-objc-image-info
-
-2010-09-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8384727> Add -reexport_symbols_list option to re-export certain symbols.
-       Added test case: unit-tests/test-cases/reexport_symbols_list
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
-       Add test case: unit-tests/test-cases/lto-dead_strip-unused
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       Warn if unaligned ARM code is detected
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/8383175> Mach-O linked by current linker don't load in VIrtualBox any more
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8304984> Linker should pick default visibility instead of warning about conflicts
-       Updated test case: unit-tests/test-cases/visibility-warning
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8249338> Enable new load commands
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8368679>  Do not pass -demangle to ld_classic
-
-2010-09-01    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8336910> iOS 4.3 armv7 should be PIE by default
-       <rdar://problem/5472933> better error message for direct access to external globals when not linking read_only_relocs
-       <rdar://problem/7927510> linker does not error on direct (static) data references to a dylib symbol     
-
--------- tagged ld64-117.11
-
-2010-09-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8385011> mask thumb bit off non lazy pointers content when parsing arm .o files
-
--------- tagged ld64-117.10
-
-2010-08-26    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8358084> 8F64 kills installtest devices
-       Don't clear thumb bit on pointers inside thumb functions if addend is negative
-
--------- tagged ld64-117.9
-
-2010-08-25    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8345038> no more audio because of broken thunk
-       Update of thumb22 b.w instruction was not clearing bits before or'ing in new ones
-
--------- tagged ld64-117.8
-
-2010-08-25    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8342028> prefetch abort in kernel mode: fault_addr=0xe58024e4
-       Don't set thumb bit on .long pointers in thumb functions that point to some offset in same function
-
--------- tagged ld64-117.7
-
-2010-08-24    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8346444> dyld-179.4 fails to link, assert in setLoadCommandsPadding()
-       Fix linker to always put __text first before other code-only sections
-
--------- tagged ld64-117.6
-
-2010-08-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8339702> ld no longer output static archive dependencies for dyld for B&I
-       Add test case unit-tests/test-cases/dependency-logging
-
--------- tagged ld64-117.5
-
-2010-08-20    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8309595> SWB: ld64-117.1 on 8F54: Assertion failed:
-       UTF16 CFStrings were not coalesced correctly when gcc built the .o files and the
-       last string in the __ustring section only had a single zero byte at the end.
-       
--------- tagged ld64-117.4
-
-2010-08-19    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8326544> DTSJ1J105: SpringBoard crashes on boot
-       Fix order file to move aliases even when subsections_via_symbols it used
-       Update test case unit-tests/test-cases/order_file
-
-2010-08-17    Nick Kledzik    <kledzik@apple.com>
-
-       Fix resolver functions to survive ld -r.
-       Warn if resolver functions are made non-external.
-
-2010-08-17    Nick Kledzik    <kledzik@apple.com>
-
-       Make it an error for resolver functions to be used in anything but a dylib.
-
--------- tagged ld64-117.3
-
-2010-08-17    Nick Kledzik    <kledzik@apple.com>
-
-       Fix thumb resolver functions
-       Enable updward dylibs and symbol re-exports for iOS 4.2
-
-2010-08-16    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
-       Rearrange LINKEDIT chunks in -preload mode
-
--------- tagged ld64-117.2
-
-2010-08-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
-       Add LC_UNIXTHREAD to -preload
-
-2010-08-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8309530> SWB: ld64-117.1 on 8F54: Assertion failed: (categoryAtom->size() == Category<A>::size())
-       gcc-4.0 uses 'L' labels on categories.  This merges them onto previous data and disable category optimzation
-
-2010-08-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8309917> SWB: ld64-117.1 on 8F54: bad category optimization
-       Disable category optimization for i386 and arm until further testing
-
-2010-08-14    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8309608> SWB: ld64-117.1 on 8F54: address not in any section
-       Handle pointer diff to stub for weak hidden function
-
-2010-08-13    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
-
--------- tagged ld64-117.1
-
-2010-08-11    Nick Kledzik    <kledzik@apple.com>
-
-       Make missing exported symbols a warning to help adoption of new linker
-
-2010-08-11    Nick Kledzik    <kledzik@apple.com>
-
-       Add ExternalRelocationsAtom<>::pointerReloc() to more easily support kext bundles
-
-2010-08-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8210380> SWB: ld64-116.2 fix branch to label-4
-
-2010-08-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8260073> Error with empty non_lazy_symbol_pointers section
-
-2010-08-06    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7977374> Add command line options to control symbol weak-def-bit on exported symbols
-
--------- tagged ld64-117
-
-2010-07-28    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8243431> split seg info wrong for x86_64 stub helpers
-
-2010-07-26    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8237436> __nlcatlist categories should not be optimized
-
-2010-07-23    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8179273> ld64 assertion on object file
-
-2010-07-21    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7435296> Reorder sections to reduce page faults in object files
-
-2010-06-30    Nick Kledzik    <kledzik@apple.com>
-
-       Support resolver functions in iOS dylibs
-
--------- tagged ld64-116.2
-
-2010-06-30    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/8138287> C programs get objc GCness from dylibs
-       Update: unit-tests/test-cases/objc-gc-checks
-
--------- tagged ld64-116.1
-
-2010-06-22    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8111013> address range check should not apply to preload executables
-
-2010-06-22    Nick Kledzik    <kledzik@apple.com>
-
-       Warn instead of error when CPU_SUBTYPE_ARM_ALL .o files used.
-
-2010-06-22    Nick Kledzik    <kledzik@apple.com>
-
-       Fix assert in objc category optimzation.  Metaclass also has copy of propery list to update.
-
-2010-06-22    Nick Kledzik    <kledzik@apple.com>
-
-       Fix crash in -r mode with -alias.
-
--------- tagged ld64-116
-
-2010-06-21    Nick Kledzik    <kledzik@apple.com>
-
-       Add support for -ios_version_min as an alias for -iphoneos_version_min
-
-2010-06-21    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7687304> linker could merge method lists from class and its categories
-       Added test case: unit-tests/test-cases/objc-category-optimize
-       Added option: -no_objc_category_merging to disable
-
-2010-06-21    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8113877> i386 TLV PIC reloc content is negated
-
-2010-06-15    Nick Kledzik    <kledzik@apple.com>
-
-       Added better error messages and asserts for bad thread local object files
-
-2010-06-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8076986> 'rebase' makes timestamps invalid/unreadable for GDB
-
-2010-06-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7966333> executable has no debug symbols when compiled with LTO
-       Added test case: unit-tests/test-cases/lto-object_path
-
-2010-06-09    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7702923> stop promoting hidden referenced dynamically symbols to global
-       Updated test case: unit-tests/test-cases/main-stripped
-
-2010-06-04    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6144674> ER: individual symbol re-exports
-       Added test case: unit-tests/test-cases/re-export-symbo
-
-2010-06-03    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7474224> add functions start info to LINKEDIT
-       * Support added but not on by default.  Use -function_starts to enable.
-       * Added test case: unit-tests/test-cases/function-start
-
-2010-06-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5674241> ER: add load command for min OS version
-       * Support added but not on by default.  Use -version_load_command to enable.
-
-2010-06-02    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/8040089> provide better undefined symbol error message
-
-2010-05-28    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7780438> ld should also merge file attributes from lazy loaded archives
-       * Move attribute gathering from InputFiles to Resolver
-
-2010-05-28    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8038333> SWB: ld64-115.3: dylib on kext link line causes malformed kext
-       * allow -static after -kext on command line
-
--------- tagged ld64-115.3
-
-2010-05-26    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8024702> strip of .o files removes __objc_imageinfo section
-       * Added test case:  unit-tests/test-cases/dwarf-strip-objc
-
-2010-05-25    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8023624> crash when parsing local vanilla reloc to weak def
-
--------- tagged ld64-115.2
-
-2010-05-21    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8012536> switch back to using ld_classic for -static arm code
-       
-
-2010-05-21    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8012549> warn instead of error when seg1addr is out of range for ARM
-
-
-2010-05-21    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/8012526> fix -undefined dynamic_lookup -nodefaults to not error about missing dyld_stub_binder
-
--------- tagged ld64-115.1
-
-2010-05-19    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix trie nodes for resolver functions to have second address be stub not helper               
-
-2010-05-19    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7996423> work around for old checksyms tools  
-       * Make i386 stub section named "__symbol_stub" instead of "__stubs"
-
-2010-05-10    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7960396> linking with LTO prints "/tmp/lto.o"
-
--------- tagged ld64-115
-
-2010-05-06    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7892392> linker loses x86_64 addend to 'L' symbols
-       * properly handle addend to 'L' symbols that are ignored
-
-2010-05-05    Nick Kledzik    <kledzik@apple.com>
-
-       * rework min OS version parsing to enable the linker to handle unknown OS versions
-
-
-2010-05-05    Nick Kledzik    <kledzik@apple.com>
-
-       * Implement magic section$start$xxx$yyyy and section$end$xxx$yyyy symbols
-       * Implement magic segment$start$xxx and segment$end$xxx symbols
-       * Add test case: unit-tests/test-cases/segment-labels
-       
-
-2010-05-03    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7173071> implement optional demangling in linker
-       * Add option: -demangle
-       * Add test case: unit-tests/test-cases/demangle
-       
-
-2010-05-03    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7931759> ld64 doesn't grok the modern-objc-ABI-on-i386 
-       * Add support for -objc_abi_version command line option
-       * Added test case: unit-tests/test-cases/objc-abi
-
-
-2010-05-03    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7929974> -alias does not work with __OBJC sections
-       * sort contents of sections with aliases
-       * Added test case: unit-tests/test-cases/objc-class-alias
-       
-
-2010-04-28    Nick Kledzik    <kledzik@apple.com>
-       
-       * <rdar://problem/4966836> Feature: Thread local storage
-       * Add test case: unit-tests/test-cases/tlv-basic
-       * Add test case: unit-tests/test-cases/tlv-dylib
-       
-
-2010-04-27    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/4383612> Accelerate needs way to dispatch based on instruction execution time characteristics.
-       * Add support for "symbol resolver" functions
-       * Add test case unit-tests/test-cases/symbol-resolver-basic
-
-
-2010-04-26    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7711820> range check fat archives
-       * check that fat file slice being used does not extend beyond end of file
-       * check that member being used does not extend beyond end of slice/file
-
-2010-04-26    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7666015> The documentation for the -allowable_client option doesn't say enough about it
-
-2010-04-26    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7854068> back out LD_NO_PIE
-
-2010-04-22    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7831043> More ICU make check failures with 0-terminated UTF16 strings
-       * Change UTF16StringSection to break into atoms just on label boundaries
-       * Added test case: unit-tests/test-cases/utf16-nul
-       
-
--------- tagged ld64-114.12
-
-2010-04-14    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7811357> Crash with messed up BNSYM
-       
-
-2010-04-07    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix crash with blank dylib stubs
-
--------- tagged ld64-114.11
-
-2010-04-07    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7798495> for ppc, add split-seg info for TEXT pointers to DATA
-       
-
-2010-04-07    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7831379> Cannot build ppc64 target with ObjC code
-
-
-2010-04-01    Nick Kledzik    <kledzik@apple.com>
-
-       * let .exp files override auto-hide so that they can be exported if needed
-
-
-2010-04-01    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
-       * added test case: unit-tests/test-cases/weak-def-auto-hide
-
-
-2010-04-01    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7818475> 'l' symbols not being automatically removed
-
-
-2010-03-31    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7808258> weak defs should not cause indirection in static executables
-       * Update test case: unit-tests/test-cases/static-executable-weak-defines
-
--------- tagged ld64-114.10
-
-2010-03-31    Nick Kledzik    <kledzik@apple.com>
-       
-       * <rdar://problem/7735120> assert with .o file with two LSDA sections
-
-
--------- tagged ld64-114.9
-
-2010-03-30    Nick Kledzik    <kledzik@apple.com>
-       
-       * <rdar://problem/7791161> L4 locks up starting a second processor, works fine with old linker
-       * properly get addend from content in x86_64 substractor when target is direct
-       
-
-2010-03-29    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7805172> ld should excludes debug notes when computing UUID
-       * added test case: unit-tests/test-cases/dwarf-debug-notes-uuid
-
--------- tagged ld64-114.8
-
-2010-03-26    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7788474> __objc_catlist section loses don't dead strip bit in ld -r mode
-       * Update test case unit-tests/test-cases/static-executable
-
--------- tagged ld64-114.7
-       
-2010-03-25    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7796313> Support LD_NO_PIE again
-
-2010-03-25    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7765885> Rosetta crashes on launch in 11A133a
-       * Fix -segaddr __TEXT to cause other floating segments to be contiguous with TEXT
-
-2010-03-24    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7786326> Page Zero segment seems to be getting dead stripped
-
-2010-03-24    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7785574> kernel sdt dtrace probes not visible
-
--------- tagged ld64-114.6
-
-2010-03-23    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7783918> new linker makes dylibs with no __text section, causing codesign_allocate tool to fail
-       * make sure there is always a __text section in dylibs and bundles
-
--------- tagged ld64-114.5
-
-2010-03-22    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7767311> missing __objc_imageinfo section
-       * Real fix will be in 7780438.  For now have Resolver also accumulate objc constraint info
-       
-
-2010-03-19    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7772740> ld64-114 does not error on missing exported symbols with -dead_strip
-
--------- tagged ld64-114.4
-       
-2010-03-16    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7762146> dyld missing LC_ID_DYLINKER
-       
--------- tagged ld64-114.3
-
-2010-03-15    Nick Kledzik    <kledzik@apple.com>
-
-       * force i386 kexts to be built with ld_classic
-       * preserve 'l' labels in static executables
-       * sync section offsets and addresses in segments with command line addresses
-
-
--------- tagged ld64-114.2
-
-2010-03-13    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7751930> ld64-114 generates x86_64 kext external call sites with incorrect addend
-
--------- tagged ld64-114.1
-
-2010-03-12    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix dyldinfo tool to correct show ordinal info for classic linkedit
-
-2010-03-12    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7748047> ld64-114 is causing read_only_reloc verification errors for ppc
-       * Update machochecker to check this.
-
--------- tagged ld64-114
-
-2010-03-11    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7744174> i386 dylibs built with ld64-112 cause runtime errors when incorporated into the dyld shared cache
-       * Add -shared_region option to dyldinfo tool
-
--------- tagged ld64-113
-
-2010-03-11    Nick Kledzik    <kledzik@apple.com>
-
-       * Allow CPU_SUBTYPE_ARM_ALL .o files to be linked into any arm arch linkage
-
-2010-03-11    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7741238> ld64-112 with -undefined dynamic_lookup marks all symbols as being flat
-       * update test case at: unit-tests/test-cases/undefined-dynamic-lookup
-
-2010-03-10    Nick Kledzik    <kledzik@apple.com>
-
-       * prevent possible crash in warning about can't export hidden symbols
-
-2010-03-10    Nick Kledzik    <kledzik@apple.com>
-
-       * make sure split-info data is zero terminated
-
--------- tagged ld64-112
-
-2010-03-09    Nick Kledzik    <kledzik@apple.com>
-
-       * Never dead strip sections added with -sectcreate
-       * Added test case: unit-tests/test-cases/sectcreate-dead_strip
-
-
--------- tagged ld64-111
-
-2010-03-03    Nick Kledzik    <kledzik@apple.com>
-
-       * Add support for "-arch arm -force_cpusubtype_ALL" to keep gcc building
-
-2010-03-02    Nick Kledzik    <kledzik@apple.com>
-
-       * Add some checking to the use of upward dylibs
-
--------- tagged ld64-110
-
-2010-03-01    Nick Kledzik    <kledzik@apple.com>
-
-       * Don't coalesce cstrings across segments
-
-2010-03-01    Nick Kledzik    <kledzik@apple.com>
-
-       * Emulate previous linker bug where hidden symbols with dynamically-referenced
-        bit were promoted to global.
-       * Added test case: unit-tests/test-cases/unstrippable-symbols
-
--------- tagged ld64-109.1
-
-2010-02-26    Nick Kledzik    <kledzik@apple.com>
-
-       * Make sure building dyld results in a thread load command
-       
--------- tagged ld64-109
-
-2010-02-26    Nick Kledzik    <kledzik@apple.com>
-
-       * Better sorting of zero-fill sections to preserve discovery order
-       * Zero out file offsets in dynamic symbol table entries that are not used
-
-2010-02-26    Nick Kledzik    <kledzik@apple.com>
-
-       * Support pointer-diffs to zero sized atom in zero sized section 
-
-2010-02-25    Nick Kledzik    <kledzik@apple.com>
-
-       * Add support for -r mode with ppc64 
-
-2010-02-25    Nick Kledzik    <kledzik@apple.com>
-
-       * Handle multiple labels on the same coalesable literal by making an
-       atom for each label, each with the same content.
-       * Add test case: unit-tests/test-cases/literals-labels
-       
-
-2010-02-25    Nick Kledzik    <kledzik@apple.com>
-
-       * Handle old ppc .o files that have stubs to static functions
-
-2010-02-25    Nick Kledzik    <kledzik@apple.com>
-
-       * Add basic ppc64 support
-
-2010-02-24    Nick Kledzik    <kledzik@apple.com>
-
-       * Range check TOC entries in archives
-
-
-2010-02-23    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix spurious dylib re-export warnings that are just regular linkage cycles
-
-
-2010-02-23    Nick Kledzik    <kledzik@apple.com>
-
-       * re-partition bits in mach_o::relocatable::Atom ivars to allow more functions per file
-
-
-2010-02-22    Nick Kledzik    <kledzik@apple.com>
-
-       * re-partition bits in mach_o::relocatable::Atom ivars to allow more fixups per function
-       
-
-2010-02-22    Nick Kledzik    <kledzik@apple.com>
-
-       * Handle re-exported dylibs that are re-exported again
-       * Added test case: unit-tests/test-cases/re-export-layers
-       
-
-2010-02-22    Nick Kledzik    <kledzik@apple.com>
-
-       * Properly handle X86_64_RELOC_SUBTRACTOR with non-external target symbol
-       
-
--------- tagged ld64-108
-
-2010-02-17    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7658740> ER: Support upward dylib dependencies
-       * Add test case:  unit-tests/test-cases/dylib-upward
-       
-
-2010-02-17    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7401775> ld(1) man page typo
-       * <rdar://problem/7230340> Linker (ld) man page typo: "unredable" in -pagezero_size option description
-       * <rdar://problem/7207483> Typo in ld(1) man page, "-x" option
-       * <rdar://problem/6239264> man ld: Change "if" -> "is"
-       * <rdar://problem/7393216> DOC: ld(1) mentions -dynamiclib when it means -dylib
-       
-
-2010-02-17    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7625461> Wordsmith ld warning about missing directories
-
-
-2010-02-17    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix -umbrella to work when umbrella is a dylib instead of a framework
-       * Add test case:  unit-tests/test-cases/umbrella-dylib
-       
-
--------- tagged ld64-107
-
-2010-02-16    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix bugs with -preload
-
-
-2010-02-16    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix dylib re-export cylce detection
-
-
-2010-02-16    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/6018216> -ObjC not pulling in members with categories only
-       * scan for non-zero __objc_catlist section in archive members when -ObjC is used
-       * Added test case: unit-tests/test-cases/objc-category-archive
-       
-       
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7398610> ld glibly removes /dev/null
-
-       
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7196255> Linker should be able to validate GC intentions
-       * Add -objc_gc and -objc_gc_only. Error when used and RR based .o file is linked in
-       * Update test case:  unit-tests/test-cases/objc-gc-checks
-
-
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7421695> Linker should provide a way to mark binaries that support compaction
-       * Added -objc_gc_compaction option
-       * Update test case:  unit-tests/test-cases/objc-gc-checks
-       
-
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7546367> ER: Need a way to detect weak exports in dev tools
-       * implement -warn_weak_exports
-
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * Add support for LD_DYLD_PATH
-
-
-2010-02-15    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7636072> cfstring backing store points to global cstring
-       * Force all by-name references in cfstring to be direct references
-       * add test case: unit-tests/test-cases/cfstring-and-cstring
-       
-
--------- tagged ld64-106
-
-2010-02-12    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7644673> Assertion failed: when class is translation unit scoped
-       * added test case unit-tests/test-cases/objc-visibility
-       
-
-2010-02-12    Nick Kledzik    <kledzik@apple.com>
-
-       * <rdar://problem/7644828> crash with missing crt?
-
-
-2010-02-12    Nick Kledzik    <kledzik@apple.com>
-
-       * Suppress indirect symbol table in static executables
-       
-
-2010-02-12    Nick Kledzik    <kledzik@apple.com>
-
-       * Rework CIE parsing to work with icc generated code
-
-
-2010-02-11    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix creation of debug notes
-       * Tweak unit-tests/test-cases/dwarf-debug-notes to match llvm symbol layout
-
-
-2010-02-11    Nick Kledzik    <kledzik@apple.com>
-
-       * Don't assert when infering ppc subtype that is ALL.
-       * Fix spurious warning about mismatched subtypes, when subtype is inferred
-
-
--------- tagged ld64-105
-
-2010-02-11    Nick Kledzik    <kledzik@apple.com>
-
-       * Use symbolic constants for bit field sizes
-
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Handle out of order sections in .o files
-
-
--------- tagged ld64-104
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Rename __tentative internal section name to __comm/tent to sort like __common
-       * Fix test case in unit-tests/test-cases/tentative-to-real-r
-
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Better warning messages about mismatched architectures
-       
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Gracefully ignore if there are >8000 line info per function in debug info
-
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Properly handle when regular definition is weak_imported
-       * Add unit-tests/test-cases/weak_import-local
-
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Don't try to coalesce zero length cstrings in mach-o parser.
-       
-
-2010-02-10    Nick Kledzik    <kledzik@apple.com>
-
-       * Add work around for llvm using L labels for backing string of CFString with -fwritable-strings
-       
-
-2010-02-09    Nick Kledzik    <kledzik@apple.com>
-
-       * Ignore labels in __gcc_except_tab section
-       * Properly apply local relocations to __eh_frame section so CFI parser works
-       * Update unit-tests/test-cases/eh-stripped-symbols to reproduce problem
-
-
-2010-02-09    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix file offset computation with large zero-fill sections
-        
-
-2010-02-09    Nick Kledzik    <kledzik@apple.com>
-
-       * Force global 'l' to be hidden 
-       * Add test case with objc properties: unit-tests/test-cases/objc-properties
-
-
--------- tagged ld64-103
-
-2010-02-04    Nick Kledzik    <kledzik@apple.com>
-
-       * Temporarily change assert() to call exit(1) instead of abort() 
-
-
-2010-02-04    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix another case in -r mode where the vmsize was less that filesize
-       
-       
-2010-02-04    Nick Kledzik    <kledzik@apple.com>
-
-       * Fix assert when generating GSYM stab debug notes
-       
-
-2010-02-04    Nick Kledzik    <kledzik@apple.com>
-
-       * Add SRCROOT to crash logs
-
-
-2010-02-04    Nick Kledzik    <kledzik@apple.com>
-
-       * Remove architectureName() from InputFiles
-
-
--------- tagged ld64-102
-
-2010-02-03    Nick Kledzik    <kledzik@apple.com>
-
-       * Add follow-on reference from symbol text atom to non-symboled text atom
-
-
--------- tagged ld64-101
-
-2010-01-29    Nick Kledzik    <kledzik@apple.com>
-
-       * fix -alias symbols to be global by default
-       
-
--------- tagged ld64-100
-
-2010-01-28    Nick Kledzik    <kledzik@apple.com>
-       
-       * Merge new/refactored linker to trunk
-       
diff --git a/compile_stubs b/compile_stubs
new file mode 100755 (executable)
index 0000000..e142e4d
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/csh
+
+# Attempt to find the architecture.
+# First look through the command line args.
+set arch=unknown
+set link_cmd=(`cat link_command`)
+while ( $#link_cmd > 0 )
+       if ( "$link_cmd[1]" == "-arch" ) then
+               set arch=$link_cmd[2]
+       endif
+       shift link_cmd
+end
+
+# look for an explicit arch file
+if ( "$arch" == "unknown" ) then
+       if ( -e arch ) then
+               set arch=`cat arch`
+       endif
+endif
+
+if ( "$arch" == "unknown" ) then
+echo "***** Unable to determine architecture."
+exit 1
+endif 
+
+# Create .dylibs for each file in the dylib_stubs directory.
+if ( -e dylib_stubs ) then
+       set files=`cd dylib_stubs ; echo *`
+       mkdir -p dylibs
+       foreach file ($files)
+               if ( ! -e dylibs/$file ) then
+                       clang -arch $arch -c -fno-builtin -o tmp_object.o -x c dylib_stubs/$file
+                       ld -arch $arch -dylib -macosx_version_min 10.1 -no_version_load_command -o dylibs/$file tmp_object.o
+               endif
+       end
+endif
+
+# Create .frameworks for each file in the framework_stubs directory.
+if ( -e framework_stubs ) then
+       set files=`cd framework_stubs ; echo *`
+       foreach file ($files)
+               if ( ! -e frameworks/$file.framework ) then
+                       clang -arch $arch -c -fno-builtin -o tmp_object.o -x c framework_stubs/$file
+                       mkdir -p frameworks/$file.framework
+                       ld -arch $arch -dylib -macosx_version_min 10.1 -no_version_load_command -o frameworks/$file.framework/$file tmp_object.o
+               endif
+       end
+endif
+
+# Clean up.
+rm -f tmp_object.o
diff --git a/doc/design/bindings.png b/doc/design/bindings.png
new file mode 100644 (file)
index 0000000..7a56388
Binary files /dev/null and b/doc/design/bindings.png differ
diff --git a/doc/design/hello.png b/doc/design/hello.png
new file mode 100644 (file)
index 0000000..9140e16
Binary files /dev/null and b/doc/design/hello.png differ
diff --git a/doc/design/linker.html b/doc/design/linker.html
new file mode 100644 (file)
index 0000000..0e39f2f
--- /dev/null
@@ -0,0 +1,423 @@
+<html>
+<head>
+  <title>Linker</title>
+</head>
+<body>
+
+
+<h1>
+  Inside the Linker 
+</h1>
+<div class="doc_author">
+  <p>Written by <a href="mailto:kledzik@apple.com">Nick Kledzik</a></p>
+</div>
+
+
+<h2>
+  <a name="introduction">Introduction</a>
+</h2>
+
+<p>The Darwin linker is a new generation of linker.  It is not "section" based
+like traditional linkers which mostly just interlace sections from multiple
+object files into the output file.  The Darwin linker is based on "Atoms".
+Traditional section based linking work well for simple linking, but their model
+makes advanced linking features difficult to implement.  Features like dead code 
+stripping, reordering functions for locality, and C++ coalescing require the
+linker to work at a finer grain.
+</p>
+
+<p>An atom is an indivisible chunk of code or data.  An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc.  An atom also
+has a list of Fixups.  A Fixup contains: a kind, an optional offset, an optional
+addend, and an optional target atom.</p>
+
+<p>The Atom model allows the linker to use standard graph theory models for 
+linking data structures.  Each atom is a node, and each Fixup is an edge. 
+The feature of dead code stripping is implemented by following edges to mark
+all live atoms, and then delete the non-live atoms.</p>
+<br>
+<h2>
+  <a name="Atom model">Atom model</a>
+</h2>
+
+<p>An atom is an indivisible chuck of code or data.  Typically each user
+written function or global variable is an atom.  In addition, the compiler may
+emit other atoms, such as for literal c-strings or floating point constants, or
+for runtime data structures like dwarf unwind info or pointers to initializers.
+</p>
+
+<p>A simple "hello world" object file would be modeled like this:</p>
+<img src="hello.png" alt="hello world graphic"/>
+<p>There are two atoms: main and an anonymous atom containing the c-string
+literal "hello world".  The Atom "main" has two fixups.  One is the call site
+for the call to printf, and the other is a fixup for the instruction that loads
+the address of the c-string literal. </p>
+
+<br>
+<h2>
+  <a name="File model">File model</a>
+</h2>
+
+<p>The linker views the input files as basically containers of Atoms and Fixups,
+ and just a few attributes of their own.  The linker works with three kinds
+of files: object files, static libraries, and dynamic libraries.  Each kind
+of file has reader object which presents the file in the model expected by 
+the linker.</p>
+<h4> <a>Object File</a> 
+</h4>
+An object file is just a container of atoms.  When linking with
+an object file, all atoms are added to the initial graph of atoms.
+
+<h4> <a>Static Library (Archive)</a> 
+</h4>
+This is the traditional unix static archive which is just a collection of
+object files with a "table of contents". When linking with a static library,
+by default nothing is added to the initial graph of atoms. Instead, if there
+are unresolved references (dangling edges) in the master graph of all atoms, 
+and the table of contents for a static library says that one of the object files 
+in the library defines one of the missing symbols (dangling edge), 
+the set of atoms from the specified object file in the static library is added 
+to the master graph of atoms. 
+
+<h4> <a>Dynamic Library (Shared Object)</a> 
+</h4>
+Dynamic libraries are unique in that the don't directly add add any atoms.  
+Their purpose is to check at build time that all references are resolved and
+provide a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. 
+The way this is modeled in the linker is that a dynamic library contributes
+no atoms to the initial graph of atoms.  Instead, (like static libraries) if
+there are unresolved references (dangling edges) in the master graph of all atoms, 
+if a dynamic library exports a required symbol, then a "proxy" atom is 
+instantiated by the linker.  The proxy atom allows the master atom graph to have
+all edges resolved and also records from which dynamic library a symbol came.</p>
+
+<br>
+<h2>
+  <a name="Linking Steps">Linking Steps</a>
+</h2>
+<p>Through the use of abstract Atoms, the core of linking is architecture 
+independent and file format independent.  All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.</p>
+<p>The overall steps in linking are:<p>
+<ol>
+  <li>Command line processing</li>
+  <li>Parsing input files</li>
+  <li>Resolving</li>
+  <li>Passes/Optimizations</li>
+  <li>Generate output file</li>
+</ol>
+
+<p>The Resolving and Passes steps are done purely on the master graph of atoms, 
+so they have no notion of file formats such as mach-o or ELF.</p>
+
+<h4> <a>Resolving</a> 
+</h4>
+<p>The resolving step takes all the atoms graphs from each object file and 
+combines them into one master object graph.  Unfortunately, it is not as simple
+as appending the atom list from each file into one big list.  There are many
+cases where atoms need to be coalesced.  That is, two or more atoms need to 
+be coalesced into one atom.  This is necessary to support: C language
+ "tentative definitions", C++ weak symbols for templates and inlines defined
+in headers, and for merging copies of constants like c-strings and floating
+point constants.</p>
+
+<p>The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols.  By-content is used for constant data
+that can be merged. </p>
+
+<p>When one atom has a reference (FixUp) to another atom, there is also a binding
+type: by-name, direct, or indirect. A Fixup contains a tagged union that if
+the binding type is by-name, the union field is a pointer to a c-string.  If
+the binding type is direct, the union is a pointer to an Atom.  If the binding
+type is indirect, the union is a index into a table of pointers to Atoms. Below
+is a graphical representation of the binding types:</p>
+<img src="bindings.png" alt="binding types graphic"/>
+
+<p>Input file Atoms contain only direct and by-name references.  Direct 
+references are used for atoms defined in the same object file for which the 
+target atom is either unnamed or cannot change.  For instance, calling 
+a static function in a translation unit will result in a direct reference 
+to the static functions's atom.  Also the FDE (dwarf unwind info) for a function
+has a direct reference to its function.  On the other hand references to 
+global symbols (e.g. call to printf) use by-name binding in object files.
+</p>
+
+<p>The resolving process maintains some global linking "state", including:
+a "symbol table" which is a map from c-string to Atom*, an indirect symbol
+table which is a growable array of Atom*, and for each kind of coalesable
+constants there is a content to Atom* map.  With these data structures,
+the linker walks all atoms in all input files. For each
+atom, it checks if the atom should be in one symbol table or one of the 
+coalescing tables.  If so, it attempts to add the atom.  If there already is
+a matching atom in that table, that means the current atom needs to be 
+coalesced with the found atom.  
+</p>
+
+<p>To support coalescing, all references to coalesable atoms are changed to
+indirect binding and an entry is added to the indirect table which points
+to the current chosen atom.  When all input atoms have been processed by
+the resolver, there should be only direct and indirect bindings left.  If
+there are any NULL entries in the indirect table, that means there are  
+undefined references.  The linker then looks to the supplied libraries (both
+static and dynamic) to resolve those references.  
+</p>
+
+<p>Dead code stripping (if requested) is done at the end of resolving.  The
+linker does a simple mark-and-sweep. It starts with "root" atoms (like "main"
+in a main executable) and follows each references and marks each Atom that
+it visits as "live".  When done, all atoms not marked "live" are removed.
+</p>
+
+<h4> <a>Passes</a> 
+</h4>
+<p>The Passes step
+is an open ended set of routines that each get a change to modify or enhance
+the master graph of atoms. Passes are only run if the master graph of 
+atoms is completely resolved (no dangling edges). 
+The current set of Passes in the Darwin linker are:</p>
+<ul>
+  <li>Objective-C optimizations (Apple)</li>
+  <li>stub (PLT) generation</li>
+  <li>GOT instantiation</li>
+  <li>TLV instantiation (Apple)</li>
+  <li>order_file optimization</li>
+  <li>branch island generation</li>
+  <li>branch shim generation</li>
+  <li>dtrace probe processing (Apple)</li>
+  <li>compact unwind encoding (Apple)</li>
+</ul>
+<p>Some of these passes are specific to Apple's runtime environments.  But many
+of the passes are applicable to any OS (such as generating branch island for 
+out of range branch instructions).</p>
+
+<p>The general structure of a pass is to walk the master graph inspecting each
+atom and doing something.  For instance, the stub pass, walks the graph looking
+for atoms with call sites to proxy atoms (e.g. call to printf).  It then
+instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for each 
+proxy atom needed, and these new atoms are added to the master graph.  Next
+all the noted call sites to proxy atoms are replaced with calls to the 
+corresponding stub atom.</p>  
+
+<h4><a>Generate Output File</a> 
+</h4>
+<p>Once the passes are done, the output file generator is given a sorted list
+of atoms.  Its job is to create the executable content file wrapper and place
+the content of the atoms into it. 
+</p>
+
+
+<h2>
+  <a name="Future Directions">Future Directions</a>
+</h2>
+
+<h4><a>Sections</a> 
+</h4>
+<p>The current use of sections in mach-o .o files over-constrains the linker.
+By default, the linker should preserve the section an atom is in.  But since
+all sections must be contiguous in the output, that limits the ability of
+the linker to order atoms for locality.  It would be helpful to enrich the
+object file with with reason something is in the section it is.  For instance,
+is the section found at runtime? Or was the use of a section just a quick
+way to group some content together?
+</p>
+<p>The ELF model for sections is a little better than mach-o because ELF
+sections have write and execute bits, whereas mach-o sections must be in some
+segment and the segment has the write and execute bits.  
+</p>
+
+<h4><a>Mach-o Object File Format</a> 
+</h4>
+<p>
+The messiest part of the linker is the mach-o parser. This is because mach-o
+is a traditional section and symbols based file format.  The parser must infer
+atom boundaries using two approaches.  The first is that some section types have  
+well defined content which the linker can parse into atoms (e.g.  __cstring, 
+__eh_frame). The other approach is a naming convention (which the compiler follows)
+by which the linker breaks sections into atoms at any non-local (not starting 
+with 'L') symbol. The processing the linker has to do parse mach-o .o files is a
+significant part of the link time. 
+</p>
+
+<p>Given that the assembler writes object files once, whereas the linker reads
+them many times (during development), it would make sense to optimize the object
+file format to be something the linker can read/parse efficiently.</p>  
+
+<h4><a>New Object File Model</a> 
+</h4>
+<p>LLVM has a nice model for its IR.  There are three representations:
+the binary bit code file, the in-memory object model, and a textual 
+representation.  LLVM contains utility possible code for converting between these
+representations.  The same model makes sense for atoms too.  There should be
+three representations for atoms: binary file, in-memory, and textual. The Darwin 
+linker already has an in-memory C++ object model for Atoms.  All we need is a 
+textual representation and binary file format.
+</p>
+<p>Note: in the darwin linker the binary format for input object files is  
+independent of the output executable format.  That is, we could have one 
+universal object file format which the linker could use as input to produce 
+mach-o, ELF, or PE executables.</p>
+<p>
+The object file binary format should be designed to instantiate into atoms
+as fast as possible.  The obvious way to do that is that the 
+file format would be an array of atoms.  The linker just mmaps in the file and
+looks at the header to see how many atoms there and instantiate that many atoms
+with the atom attribute information coming from that array.  The trick is 
+designing this in a way that can be extended as the Atom mode evolves and new
+attributes are added.
+</p>
+<p>
+In designing a textual format we want something easy for humans to read and
+easy for the linker to parse.  Since an atom has lots of attributes most of
+which are usually just the default, we should define default values for 
+every attribute so that those can be omitted from the text representation.
+One possile format is YAML.  Here is the atoms for a simple hello world
+program expressed in YAML.
+</p>
+<pre>
+---
+target-triple:   x86_64-apple-darwin11
+source:
+
+atoms:
+    - name:    _main
+      scope:   linkage-unit
+      type:    code
+      alignment: 
+          power: 4
+      content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+                 00, 00, 31, c0, 5d, c3 ]
+      fixups:
+      - offset: 07
+        kind:   pcrel32
+        target: 2
+      - offset: 0E
+        kind:   call32
+        target: _fprintf
+
+    - type:    c-string
+      merge:   by-content
+      content: [ 73, 5A, 00 ]
+
+...
+</pre>
+
+<p>One big use for the textual format will be writing test cases. The Darwin
+linker test suite test cases are written mostly in C/C++ and a few assembly
+files.  The use of C means the same test case can be compiled for different
+architectures.  But writing test cases in C is problematic because the compiler 
+may vary its output over time for its own optimization reasons which my 
+inadvertently disable or break the linker feature trying to be tested. By 
+writing test cases in the linkers own textual format, we can exactly specify 
+every attribute of every atom and thus target specific linker logic.
+</p>
+
+<h4><a>Debug Info</a> 
+</h4>
+<p>Around 2005 when Apple switched from using STABS to using DWARF for debug 
+information, we made a design decision to have the linker ignore DWARF in
+.o files.  This improves linking performance because the linker is not
+copying tons of debug info.  Instead, the linker adds "debug notes" into
+output binary that contain the paths of the original .o files. During development
+the Darwin debugger will notice the debug notes and the load the dwarf
+debug information from the original object files.  For release builds,
+a tool named dsymutil is run on the program.  It finds the debug notes and
+then the original object files, then reads, merges and optimizes all the dwarf
+debug information into one .dSYM file which can be loaded by the debugger
+if needed.</p>
+
+<p>The current way DWARF is generated is that all debug information for all
+functions in a translation unit are merged and optimized into sections based 
+on debug info kind.  For instance the mapping of instructions to source line
+numbers for all functions is compressed and put in one section. This does not
+play well in an Atom based file format.  One idea is to have the compiler
+emit some intermediate representation debug information (one which is 
+partitioned per atom) into the Atom based file format.  The linker could 
+then have code to convert that intermediate debug into to final dwarf.
+This is still an open question.</p>
+
+<h4><a>Extending Atom attributes to ELF and XCOFF</a> 
+</h4>
+<p>The current set of attributes defined for Atoms in the darwin linker
+were chosen to meet the requirements of developing code to run on iOS and 
+Mac OS X.  Below is a list of the attributes and their possible values.
+It may just require adding more values to support ELF and XCOFF.  Or there
+may need to be new attributes added to capture new functionality.
+</p>
+<ul>
+  <li>Name</li>
+  <li>Size</li>
+  <li>Section (I'd like to get rid of this)</li>
+  <li>ContentType (currently some of this comes from section)</li>
+  <ul>
+         <li>code</li>
+         <li>stub</li>
+         <li>data</li>
+         <li>zeroFill</li>
+         <li>initializerPointer</li>
+         <li>objc1Class</li>
+         <li>objc2Class</li>
+         <li>objcClassPointer</li>
+         <li>objc2CategoryList</li>
+         <li>non-lazy-pointer</li>
+         <li>lazy-pointer</li>
+         <li>constant</li>
+         <li>literal4</li>
+         <li>literal8</li>
+         <li>literal16</li>
+         <li>cstring</li>
+         <li>cstringPointer</li>
+         <li>utf16string</li>
+         <li>CFString</li>
+         <li>CFI</li>
+         <li>LSDA</li>
+         </ul>
+  </li>
+  <li>Scope
+  <ul>
+         <li>translationUnit  (static functions)</li>
+         <li>linkageUnit      (visibility hidden)</li>
+         <li>global</li>
+         </ul>
+  </li>
+  <li>DefinitionKind
+  <ul>
+         <li>regular</li>
+         <li>tentative         (ANSI C feature)</li>
+         <li>absolute          (assembly code feature)</li>
+         <li>proxy             (stand-in for dynamic library symbol)</li>
+  </ul>
+  </li>
+  <li>Combine
+  <ul>
+         <li>never</li>
+         <li>byName          (weak symbols)</li>
+         <li>byContent       (simple constants)</li>
+         <li>byContentAndReferences (complex constants)</li>
+  </ul>
+  </li>
+  <li>SymbolTableStatus
+  <ul>
+         <li>In</li>
+         <li>notIn              (anonymous)</li>
+         <li>inAsAbsolute       (assembly code feature)</li>
+         <li>inAndNeverStrip    (tell strip tool to leave)</li>
+         <li>inWithRandomName   (mach-o .o feature)</li>
+  </ul>
+  <li>Alignment
+  <ul>
+         <li>powerOfTwo</li>
+         <li>modulus</li>
+  </ul>
+  <li>NeverDeadStrip (boolean)</li>
+  <li>IsThumb (ARM specific)</li>
+</ul>
+<p>Where does dllexport fit in here?  Where does visibility protected and 
+internal fit?  Protected seems like scope=global plus the rule to not 
+indirect references to it.  Internal is like hidden plus enables some
+compiler optimizations.  I'm not sure the linker needs to know about internal.
+</p>
+
+</body>
+</html>
+
index dc2a5019cb809e0003a3b7009213a0261b639b25..a0850f6cdaf5b747c529c12e46690e65a3e4eb16 100644 (file)
@@ -743,7 +743,7 @@ Optimize stabs debug symbols to remove duplicates.  This is the default.  This o
 Write minimal stabs which causes the debugger to open and read the original .o file for full stabs.
 This style of debugging is obsolete in Mac OS X 10.5.  This option is obsolete.
 .It Fl X
-Strip local symbols that being the 'L'.  This is the default.  This option is obsolete.
+Strip local symbols that begin with 'L'.  This is the default.  This option is obsolete.
 .It Fl s
 Completely strip the output, including removing the symbol table.  This file format variant is no longer supported.  
 This option is obsolete.
index 65f20a7967e86f0647de23ce304940c466a38ee1..11e716eb78e5c97a8602095b9367fd2b54cb5ff0 100644 (file)
@@ -43,6 +43,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               B3B672421406D42800A376BB /* Snapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B672411406D42800A376BB /* Snapshot.cpp */; };
                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; };
                F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; };
                F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93CB246116E69EB003233B8 /* tlvp.cpp */; };
@@ -76,6 +77,7 @@
                F9BA955E10A233000097A440 /* huge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA955C10A233000097A440 /* huge.cpp */; };
                F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9C0D48A06DD1E1B001C7193 /* Options.cpp */; };
                F9C12EA30ED63DE7005BC69D /* dyldinfo.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */; };
+               F9CC24191461FB4300A92174 /* blob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CC24141461FB4300A92174 /* blob.cpp */; };
                F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EA72D4097454FF008B4F1D /* machochecker.cpp */; };
                F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
                F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-               C02A29DE0953B26E001FB8C1 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
+               B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; };
+               B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; };
+               B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; };
                F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
                F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; };
                F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; };
                F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; };
                F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; };
                F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; };
+               F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; };
+               F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; };
+               F9CC24161461FB4300A92174 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = "<group>"; };
+               F9CC24171461FB4300A92174 /* memutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memutils.h; sourceTree = "<group>"; };
+               F9CC24181461FB4300A92174 /* superblob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = superblob.h; sourceTree = "<group>"; };
+               F9CCF761144CE1AD007CB524 /* create_configure */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = create_configure; path = src/create_configure; sourceTree = "<group>"; };
                F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; };
                F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; };
                F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/ld/debugline.c; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
                F9023C2C06D5A227001BBF46 = {
                        isa = PBXGroup;
                        children = (
-                               C02A29DE0953B26E001FB8C1 /* ChangeLog */,
                                F9B813A80EC27B6300F94C13 /* abstraction */,
                                F9B813AD0EC27B8500F94C13 /* ld */,
                                F9B813B00EC27B9E00F94C13 /* other */,
                                F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */,
                                F989D3AA10684F5B0014B60C /* LinkEdit.hpp */,
                                F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */,
+                               F9CC24131461FB4300A92174 /* code-sign-blobs */,
                                F9AA650B1051BD2B003E3539 /* passes */,
                                F9AA65861051E750003E3539 /* parsers */,
                                F933DC37092A82480083EAC8 /* Architectures.hpp */,
                                F9EA7582097882F3008B4F1D /* debugline.c */,
                                F9EA7583097882F3008B4F1D /* debugline.h */,
+                               B3B672411406D42800A376BB /* Snapshot.cpp */,
+                               B3B672441406D44300A376BB /* Snapshot.h */,
                        );
                        name = ld;
                        sourceTree = "<group>";
                F9B813B00EC27B9E00F94C13 /* other */ = {
                        isa = PBXGroup;
                        children = (
+                               B3C7A09914295B9C005FC714 /* compile_stubs */,
+                               F9CCF761144CE1AD007CB524 /* create_configure */,
                                F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
                                F971EED706D5AD240041D381 /* ObjectDump.cpp */,
                                F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */,
                        name = other;
                        sourceTree = "<group>";
                };
+               F9CC24131461FB4300A92174 /* code-sign-blobs */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F9CC24141461FB4300A92174 /* blob.cpp */,
+                               F9CC24151461FB4300A92174 /* blob.h */,
+                               F9CC24161461FB4300A92174 /* endian.h */,
+                               F9CC24171461FB4300A92174 /* memutils.h */,
+                               F9CC24181461FB4300A92174 /* superblob.h */,
+                       );
+                       name = "code-sign-blobs";
+                       path = "src/ld/code-sign-blobs";
+                       sourceTree = "<group>";
+               };
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
                        isa = PBXNativeTarget;
                        buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */;
                        buildPhases = (
-                               F9E8DB4D11921594007B4D6A /* make config.h */,
+                               F9E8DB4D11921594007B4D6A /* make configure.h */,
+                               B3C7A09714295B60005FC714 /* make compile_stub string */,
                                F9023C3606D5A23E001BBF46 /* Sources */,
                                F9023C3706D5A23E001BBF46 /* Frameworks */,
                                F97F5025070D0B6300B9FCD7 /* copy man page */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */;
                        buildPhases = (
+                               F9CCF773144CE304007CB524 /* make configure.h */,
                                F971EED006D5ACF60041D381 /* Sources */,
                                F971EED106D5ACF60041D381 /* Frameworks */,
                        );
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9A3DDCF0ED762C100C590B9 /* Build configuration list for PBXNativeTarget "libprunetrie" */;
                        buildPhases = (
+                               F9CCF781144CE3DF007CB524 /* make configure.h */,
                                F9A3DDC70ED762B700C590B9 /* Sources */,
                                F9A3DE140ED76D7700C590B9 /* CopyFiles */,
                        );
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9B670050DDA176100E6D0DA /* Build configuration list for PBXNativeTarget "unwinddump" */;
                        buildPhases = (
+                               F9CCF77C144CE36B007CB524 /* make configure.h */,
                                F9B670020DDA176100E6D0DA /* Sources */,
                                F9B670040DDA176100E6D0DA /* Frameworks */,
                                F9B813870EC2659600F94C13 /* install man page */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9BA516D0ECE58DA00D1D62E /* Build configuration list for PBXNativeTarget "dyldinfo" */;
                        buildPhases = (
+                               F9CCF76B144CE2AD007CB524 /* make configure.h */,
                                F9BA515E0ECE58BE00D1D62E /* Sources */,
                                F9BA515F0ECE58BE00D1D62E /* Frameworks */,
                                F9C12EA50ED63E05005BC69D /* install man page */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */;
                        buildPhases = (
+                               F9CCF76F144CE2D6007CB524 /* make configure.h */,
                                F9EA72C8097454A6008B4F1D /* Sources */,
                                F9EA72C9097454A6008B4F1D /* Frameworks */,
                        );
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */;
                        buildPhases = (
+                               F9CCF765144CE244007CB524 /* make configure.h */,
                                F9EC77EB0A2F85F6002A3E39 /* Sources */,
                                F9EC77EC0A2F85F6002A3E39 /* Frameworks */,
                                F9B1A25E0A3A44CB00DA8FAB /* install man page */,
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
+               B3C7A09714295B60005FC714 /* make compile_stub string */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/compile_stubs",
+                       );
+                       name = "make compile_stub string";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/compile_stubs.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/csh;
+                       shellScript = "echo \"static const char *compile_stubs = \" > $DERIVED_FILE_DIR/compile_stubs.h\ncat compile_stubs | sed s/\\\"/\\\\\\\\\\\"/g | sed s/^/\\\"/ | sed s/\\$/\\\\\\\\n\\\"/ >> $DERIVED_FILE_DIR/compile_stubs.h\necho \";\" >> $DERIVED_FILE_DIR/compile_stubs.h";
+                       showEnvVarsInLog = 0;
+               };
                F96D5367094A2754008E9EE8 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/csh;
-                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# make linker relative libLTO.dylib\nmkdir -p ${BUILD_DIR}/lib\nln -sf /Developer/usr/lib/libLTO.dylib ${BUILD_DIR}/lib/libLTO.dylib\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\nsetenv LD_NO_CLASSIC_LINKER_STATIC\n\n# run full test suite\n\"$SRCROOT\"/unit-tests/run-all-unit-tests\n\nexit 0";
+                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# make linker relative libLTO.dylib\nmkdir -p ${BUILD_DIR}/lib\nln -sf /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib ${BUILD_DIR}/lib/libLTO.dylib\n\n# always use new linker\nsetenv LD_NO_CLASSIC_LINKER\nsetenv LD_NO_CLASSIC_LINKER_STATIC\n\n# run full test suite\n\"$SRCROOT\"/unit-tests/run-all-unit-tests\n\nexit 0";
                        showEnvVarsInLog = 0;
                };
                F9871A3413340B4600DB3F24 /* Platform install */ = {
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p  \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p  ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\tfi\nfi\n\n";
+                       shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p  \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p  ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\telse\n\t\tmkdir -p  ${DSTROOT}/Developer/usr/bin\n\t\tcp ${DSTROOT}/usr/bin/ld  ${DSTROOT}/Developer/usr/bin\n\tfi\nfi\n\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9CCF765144CE244007CB524 /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9CCF76B144CE2AD007CB524 /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9CCF76F144CE2D6007CB524 /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9CCF773144CE304007CB524 /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9CCF77C144CE36B007CB524 /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
                        showEnvVarsInLog = 0;
                };
-               F9E8DB4D11921594007B4D6A /* make config.h */ = {
+               F9CCF781144CE3DF007CB524 /* make configure.h */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "make config.h";
+                       name = "make configure.h";
                        outputPaths = (
                                "$(DERIVED_FILE_DIR)/configure.h",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "echo \"\" > ${DERIVED_FILE_DIR}/configure.h\n\nif [ -n \"${IPHONEOS_DEPLOYMENT_TARGET}\" ]; then\n\techo \"#define DEFAULT_IPHONEOS_MIN_VERSION \\\"${IPHONEOS_DEPLOYMENT_TARGET}\\\"\" >> ${DERIVED_FILE_DIR}/configure.h\nelse\n  if [ -n \"${MACOSX_DEPLOYMENT_TARGET}\" ]; then\n\techo \"#define DEFAULT_MACOSX_MIN_VERSION \\\"${MACOSX_DEPLOYMENT_TARGET}\\\"\" >> ${DERIVED_FILE_DIR}/configure.h\n  fi\nfi\n";
+                       shellScript = "${SRCROOT}/src/create_configure\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9E8DB4D11921594007B4D6A /* make configure.h */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "make configure.h";
+                       outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/bash;
+                       shellScript = "${SRCROOT}/src/create_configure\n";
                        showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
                                F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */,
                                F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */,
                                F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */,
+                               B3B672421406D42800A376BB /* Snapshot.cpp in Sources */,
+                               F9CC24191461FB4300A92174 /* blob.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                F933D91C09291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
-                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                GCC_WARN_MISSING_PARENTHESES = YES;
                                GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
                                GCC_WARN_PEDANTIC = NO;
-                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_SHADOW = NO;
                                GCC_WARN_SIGN_COMPARE = YES;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = NO;
                                GCC_WARN_UNUSED_VALUE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                HEADER_SEARCH_PATHS = (
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
-                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
+                               OTHER_LDFLAGS = (
+                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-exported_symbol,__mh_execute_header",
+                               );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
                                SECTORDER_FLAGS = "";
                F933D91D09291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
-                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                GCC_WARN_UNUSED_VALUE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                HEADER_SEARCH_PATHS = (
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                INSTALL_PATH = /usr/bin;
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
                                OTHER_LDFLAGS = (
-                                       "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib",
+                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                F933D92009291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
-                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
-                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
+                               OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = ObjectDump;
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
-                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
+                               OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = ObjectDump;
                F933D92409291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                        };
                F933D92509291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                        };
                F9849FF810B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
+                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                        };
                F9849FFA10B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
-                               ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                GCC_WARN_UNUSED_VALUE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                HEADER_SEARCH_PATHS = (
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                INSTALL_PATH = /usr/bin;
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
                                OTHER_LDFLAGS = (
-                                       "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib",
+                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
-                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
+                               OTHER_LDFLAGS = "@$(DERIVED_SOURCES_DIR)/LTO_option.txt";
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = ObjectDump;
index f4d136f95eb172e92eb1cbf34df4eb2620d56840..80a4e812dc1d1d107fae813e50727bdf94b9649a 100644 (file)
 #include <mach-o/stab.h>
 #include <mach-o/reloc.h>
 #include <mach-o/x86_64/reloc.h>
-#include <mach-o/arm/reloc.h>
 #include <mach-o/compact_unwind_encoding.h>
 #include <mach/machine.h>
 #include <stddef.h>
 
 #include "FileAbstraction.hpp"
 
+#include "configure.h"
 
 // stuff that will eventually go away once newer cctools headers are widespread
 #ifndef LC_LOAD_UPWARD_DYLIB
@@ -54,9 +54,6 @@
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
 
-#ifndef ARM_THUMB_32BIT_BRANCH
-       #define ARM_THUMB_32BIT_BRANCH  7 
-#endif
 #ifndef N_ARM_THUMB_DEF
        #define N_ARM_THUMB_DEF 0x0008 
 #endif
        #define LC_DYLD_ENVIRONMENT     0x27
 #endif
 
-// hack until newer <mach-o/arm/reloc.h> everywhere
-#define ARM_RELOC_HALF 8
-#define ARM_RELOC_HALF_SECTDIFF 9
+#ifndef LC_DATA_IN_CODE
+       #define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
+       struct data_in_code_entry {
+               uint32_t        offset;
+               uint16_t        length;
+               uint16_t        kind;
+       };
+#endif
+
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+       #define LC_DYLIB_CODE_SIGN_DRS 0x2B
+#endif
 
 #ifndef CPU_SUBTYPE_ARM_V7F
   #define CPU_SUBTYPE_ARM_V7F    ((cpu_subtype_t) 10)
   #define CPU_SUBTYPE_ARM_V7K    ((cpu_subtype_t) 12)
 #endif
 
-struct ARMSubType {
-       const char*                     subTypeName;
+
+#ifndef LC_SOURCE_VERSION
+       #define LC_SOURCE_VERSION 0x2A
+       struct source_version_command {
+               uint32_t  cmd;  /* LC_SOURCE_VERSION */
+               uint32_t  cmdsize;      /* 16 */
+               uint64_t  version;      /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
+       };
+#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
+
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+       #define LC_DYLIB_CODE_SIGN_DRS 0x2B 
+#endif 
+
+
+struct ArchInfo {
+       const char*                     archName;
+       cpu_type_t                      cpuType;
+       cpu_subtype_t           cpuSubType;
        const char*                     llvmTriplePrefix;
-       cpu_subtype_t           subType;
+       const char*                     llvmTriplePrefixAlt;
+       bool                            isSubType;
        bool                            supportsThumb2;
 };
 
-static const ARMSubType ARMSubTypes[] = {
-       { "armv4t","armv4t-",   CPU_SUBTYPE_ARM_V4T,   false },
-       { "armv5", "armv5e-",   CPU_SUBTYPE_ARM_V5TEJ, false },
-       { "armv6", "armv6-",    CPU_SUBTYPE_ARM_V6,    false },
-       { "armv7", "thumbv7-",  CPU_SUBTYPE_ARM_V7,    true },
-       { "armv7f", "thumbv7f-", CPU_SUBTYPE_ARM_V7F,   true },
-       { "armv7k", "thumbv7k-", CPU_SUBTYPE_ARM_V7K,   true },
-       { 0, NULL, false }
+static const ArchInfo archInfoArray[] = {
+#if SUPPORT_ARCH_x86_64
+       { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, "x86_64-",  "", false, false },
+#endif
+#if SUPPORT_ARCH_i386
+       { "i386",   CPU_TYPE_I386,   CPU_SUBTYPE_I386_ALL,   "i386-",    "", false, false },
+#endif
+#if SUPPORT_ARCH_armv4t
+       { "armv4t", CPU_TYPE_ARM,    CPU_SUBTYPE_ARM_V4T,    "armv4t-",  "", true,  false },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv5
+       { "armv5", CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V5TEJ,  "armv5e-",  "", true,  false },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv6
+       { "armv6", CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6,     "armv6-",   "", true,  false },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7
+       { "armv7", CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7,     "thumbv7-", "armv7-", true,  true },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+       { NULL, 0, 0, NULL, NULL, false, false }
 };
 
 
+// weird, but this include must wait until after SUPPORT_ARCH_arm_any is set up
+#if SUPPORT_ARCH_arm_any
+#include <mach-o/arm/reloc.h>
+#endif
+
+// hack until newer <mach-o/arm/reloc.h> everywhere
+#define ARM_RELOC_HALF 8
+#define ARM_RELOC_HALF_SECTDIFF 9
+
 
 
 //
@@ -1278,7 +1337,7 @@ public:
        uint32_t                version() const                                                 INLINE { return fields.version; }
        void                    set_version(uint32_t value)                             INLINE { E::set32(fields.version, value); }
 
-#ifdef LC_SOURCE_VERSION
+#ifdef DICE_KIND_DATA
        uint32_t                sdk() const                                                             INLINE { return fields.sdk; }
        void                    set_sdk(uint32_t value)                                 INLINE { E::set32(fields.sdk, value); }
 #else
@@ -1329,6 +1388,70 @@ private:
 };
 
 
+//
+// mach-o source version load command
+//
+template <typename P>
+class macho_source_version_command {
+public:
+       uint32_t                cmd() const                                                             INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)                                 INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                                 INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                             INLINE { E::set32(fields.cmdsize, value); }
+
+       uint64_t                version() const                                                 INLINE { return fields.version; }
+       void                    set_version(uint64_t value)                             INLINE { E::set64(fields.version, value); }
+
+       typedef typename P::E           E;
+private:
+       source_version_command  fields;
+};
+
+
+//
+// mach-o source version load command
+//
+template <typename P>
+class macho_entry_point_command {
+public:
+       uint32_t                cmd() const                                                             INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)                                 INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                                 INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                             INLINE { E::set32(fields.cmdsize, value); }
+
+       uint64_t                entryoff() const                                                INLINE { return fields.entryoff; }
+       void                    set_entryoff(uint64_t value)                    INLINE { E::set64(fields.entryoff, value); }
+
+       uint64_t                stacksize() const                                               INLINE { return fields.stacksize; }
+       void                    set_stacksize(uint64_t value)                   INLINE { E::set64(fields.stacksize, value); }
+
+       typedef typename P::E           E;
+private:
+       entry_point_command     fields;
+};
+
+
+
+template <typename P>
+class macho_data_in_code_entry {
+public:
+       uint32_t                offset() const                                                          INLINE { return E::get32(fields.offset); }
+       void                    set_offset(uint32_t value)                                      INLINE { E::set32(fields.offset, value); }
+
+       uint16_t                length() const                                                          INLINE { return E::get16(fields.length); }
+       void                    set_length(uint16_t value)                                      INLINE { E::set16((uint16_t&)fields.length, value); }
+
+       uint16_t                kind() const                                                            INLINE { return E::get16(fields.kind); }
+       void                    set_kind(uint16_t value)                                        INLINE { E::set16((uint16_t&)fields.kind, value); }
+
+       typedef typename P::E           E;
+private:
+       data_in_code_entry      fields;
+};
+
+
 #endif // __MACH_O_FILE_ABSTRACTION__
 
 
index 7b30cad0580d5f47bab60d8305875ef1c5f373d4..76f575a499833a063f722d5e10874a3264ace4e9 100644 (file)
@@ -360,8 +360,10 @@ static inline void processExportNode(const uint8_t* const start, const uint8_t*
                        ++edgeStrLen;
                }
                cummulativeString[curStrOffset+edgeStrLen] = *s++;
-               uint32_t childNodeOffet = read_uleb128(s, end);
-               processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen, output);        
+               uint32_t childNodeOffset = read_uleb128(s, end);
+               if (childNodeOffset == 0)
+                       throw "malformed trie, childNodeOffset==0";
+               processExportNode(start, start+childNodeOffset, end, cummulativeString, curStrOffset+edgeStrLen, output);
        }
 }
 
diff --git a/src/create_configure b/src/create_configure
new file mode 100755 (executable)
index 0000000..5375911
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+echo "" > ${DERIVED_FILE_DIR}/configure.h
+
+if [ -n "${IPHONEOS_DEPLOYMENT_TARGET}" ]; then
+       echo "#define DEFAULT_IPHONEOS_MIN_VERSION \"${IPHONEOS_DEPLOYMENT_TARGET}\"" >> ${DERIVED_FILE_DIR}/configure.h
+else
+  if [ -n "${MACOSX_DEPLOYMENT_TARGET}" ]; then
+       echo "#define DEFAULT_MACOSX_MIN_VERSION \"${MACOSX_DEPLOYMENT_TARGET}\"" >> ${DERIVED_FILE_DIR}/configure.h
+  fi
+fi
+
+if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
+       RC_SUPPORTED_ARCHS="i386 x86_64"
+fi
+
+for ANARCH in ${RC_SUPPORTED_ARCHS}
+do
+       KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,i386,x86_64,"
+       FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
+       if [ $FOUND ]; then
+               echo "#define SUPPORT_ARCH_$ANARCH  1" >> ${DERIVED_FILE_DIR}/configure.h
+       else
+               echo "#error uknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
+       fi
+done
+
+echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
+
+
+# <rdar://problem/10897631> ld64 hardcodes a reference to /Developer/usr/lib/libLTO.dylib
+if [ -n "${DT_TOOLCHAIN_DIR}" ]
+then
+       echo "-Wl,-lazy_library,${DT_TOOLCHAIN_DIR}/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+else
+       if [ -e "/Developer/usr/lib/libLTO.dylib" ]
+       then
+               echo "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+       else
+               echo "-Wl,-lazy_library,${BUILT_PRODUCTS_DIR}/../lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
+       fi
+fi
+
+
index 903a2bfb37dcda15fe6a8bb93114e353e81f3402..e425fd4d32aaf008bcfa897c8bc53ece307d8796 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -96,7 +96,9 @@ private:
        uint8_t*                                        copyRoutinesLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyUUIDLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyVersionLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copySourceVersionLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyThreadsLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyEntryPointLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyEncryptionLoadCommand(uint8_t* p) const;
        uint8_t*                                        copySplitSegInfoLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDylibLoadCommand(uint8_t* p, const ld::dylib::File*) const;
@@ -106,6 +108,8 @@ private:
        uint8_t*                                        copySubLibraryLoadCommand(uint8_t* p, const char* name) const;
        uint8_t*                                        copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const;
        uint8_t*                                        copyFunctionStartsLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
        
        uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
@@ -120,6 +124,7 @@ private:
        bool                                            _hasDyldLoadCommand;
        bool                                            _hasDylibIDLoadCommand;
        bool                                            _hasThreadLoadCommand;
+       bool                                            _hasEntryPointLoadCommand;
        bool                                            _hasEncryptionLoadCommand;
        bool                                            _hasSplitSegInfoLoadCommand;
        bool                                            _hasRoutinesLoadCommand;
@@ -130,6 +135,9 @@ private:
        bool                                            _hasSubFrameworkLoadCommand;
        bool                                            _hasVersionLoadCommand;
        bool                                            _hasFunctionStartsLoadCommand;
+       bool                                            _hasDataInCodeLoadCommand;
+       bool                                            _hasSourceVersionLoadCommand;
+       bool                                            _hasDependentDRInfo;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
        uint32_t                                        _dyldEnvironExrasCount;
@@ -161,9 +169,8 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _hasDyldInfoLoadCommand = opts.makeCompressedDyldInfo();
        _hasDyldLoadCommand = ((opts.outputKind() == Options::kDynamicExecutable) || (_options.outputKind() == Options::kDyld));
        _hasDylibIDLoadCommand = (opts.outputKind() == Options::kDynamicLibrary);
-       _hasThreadLoadCommand = _hasDyldLoadCommand || (opts.outputKind() == Options::kStaticExecutable)
-                                                                                               || (opts.outputKind() == Options::kPreload)
-                                                                                               || (opts.outputKind() == Options::kDyld);
+       _hasThreadLoadCommand = _options.needsThreadLoadCommand();
+       _hasEntryPointLoadCommand = _options.needsEntryPointLoadCommand();
        _hasEncryptionLoadCommand = opts.makeEncryptable();
        _hasSplitSegInfoLoadCommand = opts.sharedRegionEligible();
        _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL);
@@ -189,7 +196,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                        }
                        break;
                case Options::kStaticExecutable:
-                       _hasDynamicSymbolTableLoadCommand = false;
+                       _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
                        break;
                case Options::kPreload:
                        _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
@@ -199,6 +206,9 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
        _hasVersionLoadCommand = _options.addVersionLoadCommand();
        _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
+       _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
+       _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
+       _hasDependentDRInfo = _options.needsDependentDRInfo();
        _dylibLoadCommmandsCount = _writer.dylibCount();
        _allowableClientLoadCommmandsCount = _options.allowableClients().size();
        _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
@@ -328,9 +338,15 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
 
        if ( _hasVersionLoadCommand )
                sz += sizeof(macho_version_min_command<P>);
+       
+       if ( _hasSourceVersionLoadCommand )
+               sz += sizeof(macho_source_version_command<P>);
                
        if ( _hasThreadLoadCommand )
                sz += this->threadLoadCommandSize();
+
+       if ( _hasEntryPointLoadCommand )
+               sz += sizeof(macho_entry_point_command<P>);
                
        if ( _hasEncryptionLoadCommand )
                sz += sizeof(macho_encryption_info_command<P>);
@@ -377,6 +393,12 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        if ( _hasFunctionStartsLoadCommand )
                sz += sizeof(macho_linkedit_data_command<P>);
 
+       if ( _hasDataInCodeLoadCommand )
+               sz += sizeof(macho_linkedit_data_command<P>);
+
+       if ( _hasDependentDRInfo ) 
+               sz += sizeof(macho_linkedit_data_command<P>);
+               
        return sz;
 }
 
@@ -409,8 +431,14 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
        if ( _hasVersionLoadCommand )
                ++count;
 
+       if ( _hasSourceVersionLoadCommand )
+               ++count;
+               
        if ( _hasThreadLoadCommand )
                ++count;
+       
+       if ( _hasEntryPointLoadCommand )
+               ++count;
                
        if ( _hasEncryptionLoadCommand )
                ++count;
@@ -436,6 +464,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
        if ( _hasFunctionStartsLoadCommand )
                ++count;
 
+       if ( _hasDataInCodeLoadCommand )
+               ++count;
+
+       if ( _hasDependentDRInfo ) 
+               ++count;
+               
        return count;
 }
 
@@ -473,6 +507,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
        else {
                if ( _options.outputKind() == Options::kStaticExecutable ) {
                        bits |= MH_NOUNDEFS;
+                       if ( _options.positionIndependentExecutable() ) 
+                               bits |= MH_PIE;
                }
                else if ( _options.outputKind() == Options::kPreload ) {
                        bits |= MH_NOUNDEFS;
@@ -704,7 +740,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        else
                                return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
                case ld::Section::typeNonLazyPointer:
-                       return S_NON_LAZY_SYMBOL_POINTERS;
+                       if ( _options.outputKind() == Options::kKextBundle  )
+                               return S_REGULAR;
+                       else if ( (_options.outputKind() == Options::kStaticExecutable) && _options.positionIndependentExecutable() )
+                               return S_REGULAR;
+                       else
+                               return S_NON_LAZY_SYMBOL_POINTERS;
                case ld::Section::typeDyldInfo:
                        return S_REGULAR;
                case ld::Section::typeLazyDylibPointer:
@@ -715,7 +756,13 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        else
                                return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
                case ld::Section::typeInitializerPointers:
-                       return S_MOD_INIT_FUNC_POINTERS;
+                       // <rdar://problem/11456679> i386 kexts need different section type
+                       if ( (_options.outputKind() == Options::kObjectFile) 
+                                       && (strcmp(sect->sectionName(), "__constructor") == 0) 
+                                       && (strcmp(sect->segmentName(), "__TEXT") == 0) )
+                               return S_REGULAR;
+                       else
+                               return S_MOD_INIT_FUNC_POINTERS;
                case ld::Section::typeTerminatorPointers:
                        return S_MOD_TERM_FUNC_POINTERS;
                case ld::Section::typeTLVInitialValues:
@@ -1006,17 +1053,26 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
                cmd->set_cmd(LC_VERSION_MIN_MACOSX);
                cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
                cmd->set_version((uint32_t)macVersion);
-               cmd->set_sdk(0);
+               cmd->set_sdk(_options.sdkVersion());
        }
        else {
                cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
                cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
                cmd->set_version((uint32_t)iOSVersion);
-               cmd->set_sdk(0);
+               cmd->set_sdk(_options.sdkVersion());
        }
        return p + sizeof(macho_version_min_command<P>);
 }
 
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySourceVersionLoadCommand(uint8_t* p) const
+{
+       macho_source_version_command<P>* cmd = (macho_source_version_command<P>*)p;
+       cmd->set_cmd(LC_SOURCE_VERSION);
+       cmd->set_cmdsize(sizeof(macho_source_version_command<P>));
+       cmd->set_version(_options.sourceVersion());
+       return p + sizeof(macho_source_version_command<P>);
+}
 
 
 template <>
@@ -1087,6 +1143,24 @@ uint8_t* HeaderAndLoadCommandsAtom<arm>::copyThreadsLoadCommand(uint8_t* p) cons
        return p + threadLoadCommandSize();
 }
 
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
+{
+       macho_entry_point_command<P>* cmd = (macho_entry_point_command<P>*)p;
+       cmd->set_cmd(LC_MAIN);
+       cmd->set_cmdsize(sizeof(macho_entry_point_command<P>));
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       if ( _state.entryPoint->isThumb() )
+               start |= 1ULL;
+       cmd->set_entryoff(start - this->finalAddress());
+       cmd->set_stacksize(_options.hasCustomStack() ? _options.customStackSize() : 0 );
+       return p + sizeof(macho_entry_point_command<P>);
+}
+
+
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
 {
@@ -1224,6 +1298,30 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyFunctionStartsLoadCommand(uint8_t* p)
 }
 
 
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDataInCodeLoadCommand(uint8_t* p) const
+{
+       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+       cmd->set_cmd(LC_DATA_IN_CODE);
+       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+       cmd->set_dataoff(_writer.dataInCodeSection->fileOffset);
+       cmd->set_datasize(_writer.dataInCodeSection->size);
+       return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
+{
+       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+       cmd->set_cmd(LC_DYLIB_CODE_SIGN_DRS);
+       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+       cmd->set_dataoff(_writer.dependentDRsSection->fileOffset);
+       cmd->set_datasize(_writer.dependentDRsSection->size);
+       return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
 template <typename A>
 void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 {
@@ -1271,8 +1369,14 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        if ( _hasVersionLoadCommand )
                p = this->copyVersionLoadCommand(p);
 
+       if ( _hasSourceVersionLoadCommand )
+               p = this->copySourceVersionLoadCommand(p);
+
        if ( _hasThreadLoadCommand )
                p = this->copyThreadsLoadCommand(p);
+       
+       if ( _hasEntryPointLoadCommand )
+               p = this->copyEntryPointLoadCommand(p);
                
        if ( _hasEncryptionLoadCommand )
                p = this->copyEncryptionLoadCommand(p);
@@ -1318,7 +1422,13 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 
        if ( _hasFunctionStartsLoadCommand )
                p = this->copyFunctionStartsLoadCommand(p);
-               
+
+       if ( _hasDataInCodeLoadCommand )
+               p = this->copyDataInCodeLoadCommand(p);
+       
+       if ( _hasDependentDRInfo ) 
+               p = this->copyDependentDRLoadCommand(p);
 }
 
 
index 7b05a963511d92771d018df9b8048802d9a2db50..766b17cfc077d21f72ac24501a765bd538123ff9 100644 (file)
@@ -39,6 +39,8 @@
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
 #include <mach-o/fat.h>
+#include <sys/sysctl.h>
+#include <libkern/OSAtomic.h>
 
 #include <string>
 #include <map>
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
+#include "Snapshot.h"
 
+const bool _s_logPThreads = false;
 
 namespace ld {
 namespace tool {
 
-
+class IgnoredFile : public ld::File {
+public:
+       IgnoredFile(const char* pth, time_t modTime, Ordinal ord, Type type) : ld::File(pth, modTime, ord, type) {};
+       virtual bool                                            forEachAtom(AtomHandler&) const { return false; };
+       virtual bool                                            justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; };
+};
 
 
 class DSOHandleAtom : public ld::Atom {
@@ -182,7 +191,15 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
        if ( strncmp((const char*)p, "!<arch>\n", 8) == 0 )
                return "archive";
        
-       return "unsupported file format";        
+       char *unsupported = (char *)malloc(128);
+       strcpy(unsupported, "unsupported file format (");
+       for (unsigned i=0; i<len && i < 16; i++) {
+               char buf[8];
+               sprintf(buf, " 0x%2x", p[i]);
+               strcat(unsupported, buf);
+       }
+       strcat(unsupported, " )");
+       return unsupported;
 }
 
 
@@ -203,15 +220,16 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        // if fat file, skip to architecture we want
        // Note: fat header is always big-endian
        bool isFatFile = false;
+       uint32_t sliceToUse, sliceCount;
        const fat_header* fh = (fat_header*)p;
        if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                isFatFile = true;
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
-               uint32_t sliceToUse;
                bool sliceFound = false;
+               sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
                if ( _options.preferSubArchitecture() ) {
                        // first try to find a slice that match cpu-type and cpu-sub-type
-                       for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                       for (uint32_t i=0; i < sliceCount; ++i) {
                                if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture())
                                  && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) {
                                        sliceToUse = i;
@@ -222,7 +240,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                }
                if ( !sliceFound ) {
                        // look for any slice that matches just cpu-type
-                       for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                       for (uint32_t i=0; i < sliceCount; ++i) {
                                if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) {
                                        sliceToUse = i;
                                        sliceFound = true;
@@ -260,19 +278,26 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.logAllFiles                     = _options.logAllFiles();
        objOpts.convertUnwindInfo       = _options.needsUnwindInfoSection();
        objOpts.subType                         = _options.subArchitecture();
-       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, _nextInputOrdinal, objOpts);
-       if ( objResult != NULL ) 
-               return this->addObject(objResult, info, len);
+       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
+       if ( objResult != NULL ) {
+               OSAtomicAdd64(len, &_totalObjectSize);
+               OSAtomicIncrement32(&_totalObjectLoaded);
+               return objResult;
+       }
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, len, info.path, info.modTime, _nextInputOrdinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
-       if ( objResult != NULL ) 
-               return this->addObject(objResult, info, len);
-
+       objResult = lto::parse(p, len, info.path, info.modTime, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+       if ( objResult != NULL ) {
+               OSAtomicAdd64(len, &_totalObjectSize);
+               OSAtomicIncrement32(&_totalObjectLoaded);
+               return objResult;
+       }
+       
        // see if it is a dynamic library
-       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, _nextInputOrdinal, info.options.fBundleLoader, indirectDylib);
-       if ( dylibResult != NULL ) 
-               return this->addDylib(dylibResult, info, len);
+       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+       if ( dylibResult != NULL ) {
+               return dylibResult;
+       }
 
        // see if it is a static library
        ::archive::ParserOptions archOpts;
@@ -283,18 +308,17 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
-       ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts);
+       ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
        if ( archiveResult != NULL ) {
-               // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
-               if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
-                       logArchive(archiveResult);
-               return this->addArchive(archiveResult, info, len);
+               OSAtomicAdd64(len, &_totalArchiveSize);
+               OSAtomicIncrement32(&_totalArchivesLoaded);
+               return archiveResult;
        }
        
        // does not seem to be any valid linker input file, check LTO misconfiguration problems
        if ( lto::archName((uint8_t*)p, len) != NULL ) {
                if ( lto::libLTOisLoaded() ) {
-                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName());
+                       throwf("lto file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path);
                }
                else {
                        const char* libLTO = "libLTO.dylib";
@@ -302,7 +326,10 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                        char tmpPath[PATH_MAX];
                        char libLTOPath[PATH_MAX];
                        uint32_t bufSize = PATH_MAX;
-                       if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+                       if ( _options.overridePathlibLTO() != NULL ) {
+                               libLTO = _options.overridePathlibLTO();
+                       }
+                       else if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
                                if ( realpath(ldPath, tmpPath) != NULL ) {
                                        char* lastSlash = strrchr(tmpPath, '/');
                                        if ( lastSlash != NULL )
@@ -318,13 +345,13 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
 
        // error handling
        if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
-               throwf("missing required architecture %s in file", _options.architectureName());
+               throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount);
        }
        else {
                if ( isFatFile )
-                       throwf("file is universal but does not contain a(n) %s slice", _options.architectureName());
+                       throwf("file is universal (%u slices) but does not contain a(n) %s slice: %s", sliceCount, _options.architectureName(), info.path);
                else
-                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName());
+                       throwf("file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path);
        }
 }
 
@@ -409,9 +436,12 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                        if ( strcmp(dit->installName,installPath) == 0 ) {
                                try {
                                        Options::FileInfo info = _options.findFile(dit->useInstead);
+                                       _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
+                                       info.ordinal = _indirectDylibOrdinal;
                                        ld::File* reader = this->makeFile(info, true);
                                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                        if ( dylibReader != NULL ) {
+                                               addDylib(dylibReader, info);
                                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
                                                this->logDylib(dylibReader, true);
                                                return dylibReader;
@@ -438,12 +468,15 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                // note: @executable_path case is handled inside findFileUsingPaths()
                // search for dylib using -F and -L paths
                Options::FileInfo info = _options.findFileUsingPaths(installPath);
+               _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
+               info.ordinal = _indirectDylibOrdinal;
                try {
                        ld::File* reader = this->makeFile(info, true);
                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                        if ( dylibReader != NULL ) {
                                //assert(_installPathToDylibs.find(installPath) !=  _installPathToDylibs.end());
                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
+                               addDylib(dylibReader, info);
                                this->logDylib(dylibReader, true);
                                return dylibReader;
                        }
@@ -461,7 +494,8 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
 void InputFiles::createIndirectDylibs()
 {
        _allDirectDylibsLoaded = true;
-
+       _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
+       
        // mark all dylibs initially specified as required and check if they can be used
        for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
                it->second->setExplicitlyLinked();
@@ -510,10 +544,7 @@ void InputFiles::createOpaqueFileSections()
 {
        // extra command line section always at end
        for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
-               _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data,
-                                                                                                                       it->dataLen, _nextInputOrdinal));
-               // bump ordinal
-               _nextInputOrdinal++;
+               _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
        }
 
 }
@@ -643,71 +674,158 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
 InputFiles::InputFiles(Options& opts, const char** archName) 
  : _totalObjectSize(0), _totalArchiveSize(0), 
    _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
-       _options(opts), _bundleLoader(NULL), _nextInputOrdinal(1), 
-       _allDirectDylibsLoaded(false), _inferredArch(false)
+       _options(opts), _bundleLoader(NULL), 
+       _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1),
+       _exception(NULL)
 {
 //     fStartCreateReadersTime = mach_absolute_time();
        if ( opts.architecture() == 0 ) {
                // command line missing -arch, so guess arch
                inferArchitecture(opts, archName);
        }
-
-       const std::vector<Options::FileInfo>& files = opts.getInputFiles();
+#if HAVE_PTHREADS
+       pthread_mutex_init(&_parseLock, NULL);
+       pthread_cond_init(&_parseWorkReady, NULL);
+       pthread_cond_init(&_newFileAvailable, NULL);
+#endif
+       const std::vector<Options::FileInfo>& files = _options.getInputFiles();
        if ( files.size() == 0 )
                throw "no object files specified";
-       // add all direct object, archives, and dylibs
+
        _inputFiles.reserve(files.size());
+#if HAVE_PTHREADS
+       unsigned int inputFileSlot = 0;
+       _availableInputFiles = 0;
+       _parseCursor = 0;
+#endif
+       Options::FileInfo* entry;
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
-               const Options::FileInfo& entry = *it;
-               try {
-                       _inputFiles.push_back(this->makeFile(entry, false));
-               }
-               catch (const char* msg) {
-                       if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
-                               if ( opts.ignoreOtherArchInputFiles() ) {
-                                       // ignore, because this is about an architecture not in use
-                               }
-                               else {
-                                       warning("ignoring file %s, %s", entry.path, msg);
-                               }
-                       }
-                       else {
-                               throwf("in %s, %s", entry.path, msg);
-                       }
-               }
+               entry = (Options::FileInfo*)&(*it);
+#if HAVE_PTHREADS
+               // Assign input file slots to all the FileInfos.
+               // Also chain all FileInfos into one big list to set up for worker threads to do parsing.
+               entry->inputFileSlot = inputFileSlot;
+               entry->readyToParse = !entry->fromFileList || !_options.pipelineEnabled();
+               if (entry->readyToParse)
+                       _availableInputFiles++;
+               _inputFiles.push_back(NULL);
+               inputFileSlot++;
+#else
+               // In the non-threaded case just parse the file now.
+               _inputFiles.push_back(makeFile(*entry, false));
+#endif
+       }
+       
+#if HAVE_PTHREADS
+       _remainingInputFiles = files.size();
+       
+       // initialize info for parsing input files on worker threads
+       unsigned int ncpus;
+       int mib[2];
+       size_t len = sizeof(ncpus);
+       mib[0] = CTL_HW;
+       mib[1] = HW_NCPU;
+       if (sysctl(mib, 2, &ncpus, &len, NULL, 0) != 0) {
+               ncpus = 1;
+       }
+       _availableWorkers = MIN(ncpus, files.size()); // max # workers we permit
+       _idleWorkers = 0;
+       
+       if (_options.pipelineEnabled()) {
+               // start up a thread to listen for available input files
+               startThread(InputFiles::waitForInputFiles);
        }
 
-       this->createIndirectDylibs();
-       this->createOpaqueFileSections();
+       // Start up one parser thread. More start on demand as parsed input files get consumed.
+       startThread(InputFiles::parseWorkerThread);
+       _availableWorkers--;
+#else
+       if (_options.pipelineEnabled()) {
+               throwf("pipelined linking not supported on this platform");
+       }
+#endif
 }
 
 
-
-ld::File* InputFiles::addArchive(ld::File* reader, const Options::FileInfo& info, uint64_t mappedLen)
-{
-       // bump ordinal
-       _nextInputOrdinal += reader->subFileCount();
-
-       // update stats
-       _totalArchiveSize += mappedLen;
-       _totalArchivesLoaded++;
-       return reader;
+#if HAVE_PTHREADS
+void InputFiles::startThread(void (*threadFunc)(InputFiles *)) const {
+       pthread_t thread;
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       // set a nice big stack (same as main thread) because some code uses potentially large stack buffers
+       pthread_attr_setstacksize(&attr, 8 * 1024 * 1024);
+       pthread_create(&thread, &attr, (void *(*)(void*))threadFunc, (void *)this);
+       pthread_detach(thread);
+       pthread_attr_destroy(&attr);
 }
 
+// Work loop for input file parsing threads
+void InputFiles::parseWorkerThread() {
+       ld::File *file;
+       const char *exception = NULL;
+       pthread_mutex_lock(&_parseLock);
+       const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+       if (_s_logPThreads) printf("worker starting\n");
+       do {
+               if (_availableInputFiles == 0) {
+                       _idleWorkers++;
+                       pthread_cond_wait(&_parseWorkReady, &_parseLock);
+                       _idleWorkers--;
+               } else {
+                       int slot = _parseCursor;
+                       while (slot < (int)files.size() && (_inputFiles[slot] != NULL || !files[slot].readyToParse))
+                               slot++;
+                       assert(slot < (int)files.size());
+                       Options::FileInfo& entry = (Options::FileInfo&)files[slot];
+                       _parseCursor = slot+1;
+                       _availableInputFiles--;
+                       entry.readyToParse = false; // to avoid multiple threads finding this file
+                       pthread_mutex_unlock(&_parseLock);
+                       if (_s_logPThreads) printf("parsing index %u\n", slot);
+                       try {
+                               file = makeFile(entry, false);
+                       } catch (const char *msg) {
+                               if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
+                                       if ( _options.ignoreOtherArchInputFiles() ) {
+                                               // ignore, because this is about an architecture not in use
+                                       }
+                                       else {
+                                               warning("ignoring file %s, %s", entry.path, msg);
+                                       }
+                               } else {
+                                       exception = msg;
+                               }
+                               file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
+                       }
+                       pthread_mutex_lock(&_parseLock);
+                       if (_remainingInputFiles > 0)
+                               _remainingInputFiles--;
+                       if (_s_logPThreads) printf("done with index %u, %d remaining\n", slot, _remainingInputFiles);
+                       if (exception) {
+                               // We are about to die, so set to zero to stop other threads from doing unneeded work.
+                               _remainingInputFiles = 0;
+                               _exception = exception;
+                       } else {
+                               _inputFiles[slot] = file;
+                               if (_neededFileSlot == slot)
+                                       pthread_cond_signal(&_newFileAvailable);
+                       }
+               }
+       } while (_remainingInputFiles);
+       if (_s_logPThreads) printf("worker exiting\n");
+       pthread_cond_broadcast(&_parseWorkReady);
+       pthread_cond_signal(&_newFileAvailable);
+       pthread_mutex_unlock(&_parseLock);
+}
 
-ld::File* InputFiles::addObject(ld::relocatable::File* file, const Options::FileInfo& info, uint64_t mappedLen)
-{
-       // bump ordinal
-       _nextInputOrdinal++;
 
-       // update stats
-       _totalObjectSize += mappedLen;
-       _totalObjectLoaded++;
-       return file;
+void InputFiles::parseWorkerThread(InputFiles *inputFiles) {
+       inputFiles->parseWorkerThread();
 }
+#endif
 
 
-ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info, uint64_t mappedLen)
+ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info)
 {
        _allDylibs.insert(reader);
        
@@ -750,8 +868,9 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
                                        }
                                }
                        }
-                       if ( !dylibOnCommandLineTwice && !isSymlink )
-                               warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+                       // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
+                       //if ( !dylibOnCommandLineTwice && !isSymlink )
+                       //      warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
                }
        }
        else if ( info.options.fBundleLoader )
@@ -761,106 +880,240 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
        if ( !_allDirectDylibsLoaded ) 
                this->logDylib(reader, false);
 
-       // bump ordinal
-       _nextInputOrdinal++;
-
        // update stats
        _totalDylibsLoaded++;
 
+    _searchLibraries.push_back(LibraryInfo(reader));
        return reader;
 }
 
 
-bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const
+#if HAVE_PTHREADS
+// Called during pipelined linking to listen for available input files.
+// Available files are enqueued for parsing.
+void InputFiles::waitForInputFiles()
 {
-       bool didSomething = false;
-       for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) {
-               didSomething |= (*it)->forEachAtom(handler);
-       }
-       if ( didSomething || true ) {
-               switch ( _options.outputKind() ) {
-                       case Options::kStaticExecutable:
-                       case Options::kDynamicExecutable:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomExecutable);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               if ( _options.pageZeroSize() != 0 ) 
-                                       handler.doAtom(*new PageZeroAtom(_options.pageZeroSize()));
-                               if ( _options.hasCustomStack() ) 
-                                       handler.doAtom(*new CustomStackAtom(_options.customStackSize()));
-                               break;
-                       case Options::kDynamicLibrary:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomDylib);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
-                       case Options::kDynamicBundle:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomBundle);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
-                       case Options::kDyld:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomDyld);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
-                       case Options::kPreload:
-                               // add implicit __mh_preload_header label
-                               handler.doAtom(DSOHandleAtom::_s_atomPreload);
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
-                       case Options::kObjectFile:
-                               handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
-                               break;
-                       case Options::kKextBundle:
-                               // add implicit __dso_handle label
-                               handler.doAtom(DSOHandleAtom::_s_atomAll);
-                               break;
+       if (_s_logPThreads) printf("starting pipeline listener\n");
+       try {
+               const char *fifo = _options.pipelineFifo();
+               assert(fifo);
+               std::map<const char *, const Options::FileInfo*, strcompclass> fileMap;
+               const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+               for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
+                       const Options::FileInfo& entry = *it;
+                       if (entry.fromFileList) {
+                               fileMap[entry.path] = &entry;
+                       }
+               }
+               FILE *fileStream = fopen(fifo, "r");
+               if (!fileStream)
+                       throwf("pipelined linking error - failed to open stream. fopen() returns %s for \"%s\"\n", strerror(errno), fifo);
+               while (fileMap.size() > 0) {
+                       char path_buf[PATH_MAX+1];
+                       if (fgets(path_buf, PATH_MAX, fileStream) == NULL)
+                               throwf("pipelined linking error - %lu missing input files", fileMap.size());
+                       int len = strlen(path_buf);
+                       if (path_buf[len-1] == '\n')
+                               path_buf[len-1] = 0;
+                       std::map<const char *, const Options::FileInfo*, strcompclass>::iterator it = fileMap.find(path_buf);
+                       if (it == fileMap.end())
+                               throwf("pipelined linking error - not in file list: %s\n", path_buf);
+                       Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
+                       if (!inputInfo->checkFileExists())
+                               throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
+                       pthread_mutex_lock(&_parseLock);
+                       if (_idleWorkers)
+                               pthread_cond_signal(&_parseWorkReady);
+                       inputInfo->readyToParse = true;
+                       if (_parseCursor > inputInfo->inputFileSlot)
+                               _parseCursor = inputInfo->inputFileSlot;
+                       _availableInputFiles++;
+                       if (_s_logPThreads) printf("pipeline listener: %s slot=%d, _parseCursor=%d, _availableInputFiles = %d remaining = %ld\n", path_buf, inputInfo->inputFileSlot, _parseCursor, _availableInputFiles, fileMap.size()-1);
+                       pthread_mutex_unlock(&_parseLock);
+                       fileMap.erase(it);
                }
+       } catch (const char *msg) {
+               pthread_mutex_lock(&_parseLock);
+               _exception = msg;
+               pthread_cond_signal(&_newFileAvailable);
+               pthread_mutex_unlock(&_parseLock);
        }
-       return didSomething;
 }
 
 
-bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
+void InputFiles::waitForInputFiles(InputFiles *inputFiles) {
+       inputFiles->waitForInputFiles();
+}
+#endif
+
+
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
 {
-       // check each input file 
-       for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) {
-               ld::File* file = *it;
-               // if this reader is a static archive that has the symbol we need, pull in all atoms in that module
-               // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us.
-               ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(file);
-               ld::archive::File* archiveFile = dynamic_cast<ld::archive::File*>(file);
-               if ( searchDylibs && (dylibFile != NULL) ) {
-                       //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() );
-                       if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
-                               // we found a definition in this dylib
-                               // done, unless it is a weak definition in which case we keep searching
-                               if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name))
-                                       return true;
-                               // else continue search for a non-weak definition
+       // add all direct object, archives, and dylibs
+       const std::vector<Options::FileInfo>& files = _options.getInputFiles();
+       size_t fileIndex;
+       for (fileIndex=0; fileIndex<_inputFiles.size(); fileIndex++) {
+               ld::File *file;
+#if HAVE_PTHREADS
+               pthread_mutex_lock(&_parseLock);
+               
+               // this loop waits for the needed file to be ready (parsed by worker thread)
+               while (_inputFiles[fileIndex] == NULL && _exception == NULL) {
+                       // We are starved for input. If there are still files to parse and we have
+                       // not maxed out the worker thread count start a new worker thread.
+                       if (_availableInputFiles > 0 && _availableWorkers > 0) {
+                               if (_s_logPThreads) printf("starting worker\n");
+                               startThread(InputFiles::parseWorkerThread);
+                               _availableWorkers--;
                        }
+                       _neededFileSlot = fileIndex;
+                       if (_s_logPThreads) printf("consumer blocking for %lu: %s\n", fileIndex, files[fileIndex].path);
+                       pthread_cond_wait(&_newFileAvailable, &_parseLock);
                }
-               else if ( searchArchives && (archiveFile != NULL) ) {
-                       if ( dataSymbolOnly ) {
-                               if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
-                                       if ( _options.traceArchives() ) 
-                                               logArchive(file);
-                                       // found data definition in static library, done
-                                       return true;
-                               }
+
+               if (_exception)
+                       throw _exception;
+
+               // The input file is parsed. Assimilate it and call its atom iterator.
+               if (_s_logPThreads) printf("consuming slot %lu\n", fileIndex);
+               file = _inputFiles[fileIndex];
+               pthread_mutex_unlock(&_parseLock);
+#else
+               file = _inputFiles[fileIndex];
+#endif
+               const Options::FileInfo& info = files[fileIndex];
+               switch (file->type()) {
+                       case ld::File::Reloc:
+                       {
+                               ld::relocatable::File* reloc = (ld::relocatable::File*)file;
+                               _options.snapshot().recordObjectFile(reloc->path());
                        }
-                       else {
-                               if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
-                                       if ( _options.traceArchives() ) 
-                                               logArchive(file);
-                                       // found definition in static library, done
-                                       return true;
-                               }
+                               break;
+                       case ld::File::Dylib:
+                       {
+                               ld::dylib::File* dylib = (ld::dylib::File*)file;
+                               addDylib(dylib, info);
                        }
+                               break;
+                       case ld::File::Archive:
+                       {
+                               ld::archive::File* archive = (ld::archive::File*)file;
+                               // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
+                               if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
+                                       logArchive(archive);
+                               _searchLibraries.push_back(LibraryInfo(archive));
+                       }
+                               break;
+                       case ld::File::Other:
+                               break;
+                       default:
+                       {
+                               throwf("Unknown file type for %s", file->path());
+                       }
+                               break;
                }
+               file->forEachAtom(handler);
        }
 
+       createIndirectDylibs();
+       createOpaqueFileSections();
+       
+       while (fileIndex < _inputFiles.size()) {
+               ld::File *file = _inputFiles[fileIndex];
+               file->forEachAtom(handler);
+               fileIndex++;
+       }
+    
+    switch ( _options.outputKind() ) {
+        case Options::kStaticExecutable:
+        case Options::kDynamicExecutable:
+            // add implicit __dso_handle label
+            handler.doAtom(DSOHandleAtom::_s_atomExecutable);
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            if ( _options.pageZeroSize() != 0 ) 
+                handler.doAtom(*new PageZeroAtom(_options.pageZeroSize()));
+            if ( _options.hasCustomStack() && !_options.needsEntryPointLoadCommand() ) 
+                handler.doAtom(*new CustomStackAtom(_options.customStackSize()));
+            break;
+        case Options::kDynamicLibrary:
+            // add implicit __dso_handle label
+            handler.doAtom(DSOHandleAtom::_s_atomDylib);
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            break;
+        case Options::kDynamicBundle:
+            // add implicit __dso_handle label
+            handler.doAtom(DSOHandleAtom::_s_atomBundle);
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            break;
+        case Options::kDyld:
+            // add implicit __dso_handle label
+            handler.doAtom(DSOHandleAtom::_s_atomDyld);
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            break;
+        case Options::kPreload:
+            // add implicit __mh_preload_header label
+            handler.doAtom(DSOHandleAtom::_s_atomPreload);
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            break;
+        case Options::kObjectFile:
+            handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
+            break;
+        case Options::kKextBundle:
+            // add implicit __dso_handle label
+            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            break;
+       }
+}
+
+
+bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
+{
+       // Check each input library.
+    std::vector<LibraryInfo>::const_iterator libIterator = _searchLibraries.begin();
+    
+    
+    while (libIterator != _searchLibraries.end()) {
+        LibraryInfo lib = *libIterator;
+        if (lib.isDylib()) {
+            if (searchDylibs) {
+                ld::dylib::File *dylibFile = lib.dylib();
+                //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() );
+                if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
+                    // we found a definition in this dylib
+                    // done, unless it is a weak definition in which case we keep searching
+                    _options.snapshot().recordDylibSymbol(dylibFile, name);
+                    if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) {
+                        return true;
+                    }
+                    // else continue search for a non-weak definition
+                }
+            }
+        } else {
+            if (searchArchives) {
+                ld::archive::File *archiveFile = lib.archive();
+                if ( dataSymbolOnly ) {
+                    if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
+                        if ( _options.traceArchives() ) 
+                            logArchive(archiveFile);
+                        _options.snapshot().recordArchive(archiveFile->path());
+                        // found data definition in static library, done
+                        return true;
+                    }
+                }
+                else {
+                    if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
+                        if ( _options.traceArchives() ) 
+                            logArchive(archiveFile);
+                        _options.snapshot().recordArchive(archiveFile->path());
+                        // found definition in static library, done
+                        return true;
+                    }
+                }
+            }
+        }
+        libIterator++;
+    }
+
        // search indirect dylibs
        if ( searchDylibs ) {
                for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
@@ -879,8 +1132,10 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                                if ( dylibFile->justInTimeforEachAtom(name, handler) ) {
                                        // we found a definition in this dylib
                                        // done, unless it is a weak definition in which case we keep searching
-                                       if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name))
+                    _options.snapshot().recordDylibSymbol(dylibFile, name);
+                                       if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) {
                                                return true;
+                    }
                                        // else continue search for a non-weak definition
                                }
                        }                       
@@ -904,6 +1159,11 @@ bool InputFiles::searchWeakDefInDylib(const char* name) const
        }
        return false;
 }
+       
+static bool vectorContains(const std::vector<ld::dylib::File*>& vec, ld::dylib::File* key)
+{
+       return std::find(vec.begin(), vec.end(), key) != vec.end();
+}
 
 void InputFiles::dylibs(ld::Internal& state)
 {
@@ -928,8 +1188,11 @@ void InputFiles::dylibs(ld::Internal& state)
                ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(*it);
                // only add dylibs that are not "blank" dylib stubs
                if ( (dylibFile != NULL) && ((dylibFile->installPath() != NULL) || (dylibFile == _bundleLoader)) ) {
-                       if ( dylibsOK )
-                               state.dylibs.push_back(dylibFile);
+                       if ( dylibsOK ) {
+                               if ( ! vectorContains(state.dylibs, dylibFile) ) {
+                                       state.dylibs.push_back(dylibFile);
+                               }
+                       }
                        else
                                warning("unexpected dylib (%s) on link line", dylibFile->path());
                }
@@ -938,15 +1201,30 @@ void InputFiles::dylibs(ld::Internal& state)
        if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
                for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                        ld::dylib::File* dylibFile = it->second;
-                       if ( dylibFile->implicitlyLinked() && dylibsOK ) 
-                               state.dylibs.push_back(dylibFile);
+                       if ( dylibFile->implicitlyLinked() && dylibsOK ) {
+                               if ( ! vectorContains(state.dylibs, dylibFile) ) {
+                                       state.dylibs.push_back(dylibFile);
+                               }
+                       }
                }
        }
+
+       //fprintf(stderr, "all dylibs:\n");
+       //for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+       //      const ld::dylib::File* dylib = *it;
+       //      fprintf(stderr, "    %p %s\n", dylib, dylib->path());
+       //}
+       
        // and -bundle_loader
        state.bundleLoader = _bundleLoader;
+       
+       // <rdar://problem/10807040> give an error when -nostdlib is used and libSystem is missing
+       if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() ) 
+               throw "dynamic main executables must link with libSystem.dylib";
 }
 
 
 } // namespace tool 
 } // namespace ld 
 
+
index 1842c8ec74a93cd38c4faf88c761f16453d742de..afc2077349923d5fa402caf174099e0f8c239a75 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef __INPUT_FILES_H__
 #define __INPUT_FILES_H__
 
+#define HAVE_PTHREADS 1
+
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -40,6 +42,9 @@
 #include <mach/mach_host.h>
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
 
 #include <vector>
 
@@ -58,7 +63,7 @@ public:
        virtual ld::dylib::File*        findDylib(const char* installPath, const char* fromPath);
        
        // iterates all atoms in initial files
-       bool                                            forEachInitialAtom(ld::File::AtomHandler&) const;
+       void                                            forEachInitialAtom(ld::File::AtomHandler&);
        // searches libraries for name
        bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives,  
                                                                                                                                  bool dataSymbolOnly, ld::File::AtomHandler&) const;
@@ -69,29 +74,34 @@ public:
        
        bool                                            inferredArch() const { return _inferredArch; }
        
-       uint32_t                                        nextInputOrdinal() const  { return _nextInputOrdinal++; }
-       
        // for -print_statistics
-       uint64_t                                        _totalObjectSize;
-       uint64_t                                        _totalArchiveSize;
-       uint32_t                                        _totalObjectLoaded;
-       uint32_t                                        _totalArchivesLoaded;
-       uint32_t                                        _totalDylibsLoaded;
+       volatile int64_t                        _totalObjectSize;
+       volatile int64_t                        _totalArchiveSize;
+       volatile int32_t                        _totalObjectLoaded;
+       volatile int32_t                        _totalArchivesLoaded;
+       volatile int32_t                        _totalDylibsLoaded;
        
        
 private:
        void                                            inferArchitecture(Options& opts, const char** archName);
        const char*                                     fileArch(const uint8_t* p, unsigned len);
        ld::File*                                       makeFile(const Options::FileInfo& info, bool indirectDylib);
-       ld::File*                                       addDylib(ld::dylib::File* f,        const Options::FileInfo& info, uint64_t mappedLen);
-       ld::File*                                       addObject(ld::relocatable::File* f, const Options::FileInfo& info, uint64_t mappedLen);
-       ld::File*                                       addArchive(ld::File* f,             const Options::FileInfo& info, uint64_t mappedLen);
+       ld::File*                                       addDylib(ld::dylib::File* f,        const Options::FileInfo& info);
        void                                            logTraceInfo (const char* format, ...) const;
        void                                            logDylib(ld::File*, bool indirect);
        void                                            logArchive(ld::File*) const;
        void                                            createIndirectDylibs();
        void                                            checkDylibClientRestrictions(ld::dylib::File*);
        void                                            createOpaqueFileSections();
+       
+       // for pipelined linking
+    void                      waitForInputFiles();
+       static void                                     waitForInputFiles(InputFiles *inputFiles);
+
+       // for threaded input file processing
+       void                                            parseWorkerThread();
+       static void                                     parseWorkerThread(InputFiles *inputFiles);
+       void                                            startThread(void (*threadFunc)(InputFiles *)) const;
 
        class CStringEquals {
        public:
@@ -105,9 +115,41 @@ private:
        InstallNameToDylib                      _installPathToDylibs;
        std::set<ld::dylib::File*>      _allDylibs;
        ld::dylib::File*                        _bundleLoader;
-       mutable uint32_t                        _nextInputOrdinal;
        bool                                            _allDirectDylibsLoaded;
        bool                                            _inferredArch;
+    int                       _fileMonitor;
+    struct strcompclass {
+        bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
+    };
+
+       // for threaded input file processing
+#if HAVE_PTHREADS
+       pthread_mutex_t                         _parseLock;
+       pthread_cond_t                          _parseWorkReady;                // used by parse threads to block for work
+       pthread_cond_t                          _newFileAvailable;              // used by main thread to block for parsed input files
+       int                                                     _availableWorkers;              // number of remaining unstarted parse threads
+       int                                                     _idleWorkers;                   // number of running parse threads that are idle
+       int                                                     _neededFileSlot;                // input file the resolver is currently blocked waiting for
+       int                                                     _parseCursor;                   // slot to begin searching for a file to parse
+       int                                                     _availableInputFiles;   // number of input fileinfos with readyToParse==true
+#endif
+       const char *                            _exception;                             // passes an exception message from parse thread to main thread
+       int                                                     _remainingInputFiles;   // number of input files still to parse
+       
+       ld::File::Ordinal                       _indirectDylibOrdinal;
+    
+    class LibraryInfo {
+        ld::File* _lib;
+        bool      _isDylib;
+    public:
+        LibraryInfo(ld::dylib::File* dylib) : _lib(dylib), _isDylib(true) {};
+        LibraryInfo(ld::archive::File* dylib) : _lib(dylib), _isDylib(false) {};
+
+        bool isDylib() { return _isDylib; }
+        ld::dylib::File *dylib() { return (ld::dylib::File*)_lib; }
+        ld::archive::File *archive() { return (ld::archive::File*)_lib; }
+    };
+    std::vector<LibraryInfo>  _searchLibraries;
 };
 
 } // namespace tool 
index 7bca2e309a0f69ddc87905f168eddb6332e0d745..e43608283150ba8909fef71ee024af65606eda5d 100644 (file)
@@ -37,6 +37,7 @@
 #include "ld.hpp"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
+#include "code-sign-blobs/superblob.h"
 
 namespace ld {
 namespace tool {
@@ -1249,7 +1250,6 @@ void SplitSegInfoAtom<A>::encode() const
        _64bitPointerLocations.clear();
 }
 
-
 template <typename A>
 class FunctionStartsAtom : public LinkEditAtom
 {
@@ -1292,6 +1292,9 @@ void FunctionStartsAtom<A>::encode() const
                        std::vector<const ld::Atom*>& atoms = sect->atoms;
                        for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
                                const ld::Atom* atom = *ait;
+                               // <rdar://problem/10422823> filter out zero-length atoms, so LC_FUNCTION_STARTS address can't spill into next section
+                               if ( atom->size() == 0 )
+                                       continue;
                                uint64_t nextAddr = atom->finalAddress();
                                if ( atom->isThumb() )
                                        nextAddr |= 1; 
@@ -1313,6 +1316,194 @@ void FunctionStartsAtom<A>::encode() const
 }
 
 
+// <rdar://problem/9218847> Need way to formalize data in code
+template <typename A>
+class DataInCodeAtom : public LinkEditAtom
+{
+public:
+                                                                                               DataInCodeAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "data-in-code info"; }
+       // overrides of LinkEditAtom
+       virtual void                                                            encode() const;
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       struct FixupByAddressSorter
+       {
+                bool operator()(const ld::Fixup* left, const ld::Fixup* right)
+                {
+                         return (left->offsetInAtom < right->offsetInAtom);
+                }
+       };
+
+       void encodeEntry(uint32_t startImageOffset, int len, ld::Fixup::Kind kind) const {
+               //fprintf(stderr, "encodeEntry(start=0x%08X, len=0x%04X, kind=%04X\n", startImageOffset, len, kind);
+               do {
+                       macho_data_in_code_entry<P> entry;
+                       entry.set_offset(startImageOffset);
+                       entry.set_length(len);
+                       switch ( kind ) {
+                               case ld::Fixup::kindDataInCodeStartData:
+                                       entry.set_kind(1);
+                                       break;
+                               case ld::Fixup::kindDataInCodeStartJT8:
+                                       entry.set_kind(2);
+                                       break;
+                               case ld::Fixup::kindDataInCodeStartJT16:
+                                       entry.set_kind(3);
+                                       break;
+                               case ld::Fixup::kindDataInCodeStartJT32:
+                                       entry.set_kind(4);
+                                       break;
+                               case ld::Fixup::kindDataInCodeStartJTA32:
+                                       entry.set_kind(5);
+                                       break;
+                               default:
+                                       assert(0 && "bad L$start$ label to encode");
+                       }
+                       uint8_t* bp = (uint8_t*)&entry;
+                       this->_encodedData.append_byte(bp[0]);
+                       this->_encodedData.append_byte(bp[1]);
+                       this->_encodedData.append_byte(bp[2]);
+                       this->_encodedData.append_byte(bp[3]);
+                       this->_encodedData.append_byte(bp[4]);
+                       this->_encodedData.append_byte(bp[5]);
+                       this->_encodedData.append_byte(bp[6]);
+                       this->_encodedData.append_byte(bp[7]);
+                       // in rare case data range is huge, create multiple entries
+                       len -= 0xFFF8;
+                       startImageOffset += 0xFFF8;
+               } while ( len > 0 );
+       }
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section DataInCodeAtom<A>::_s_section("__LINKEDIT", "__dataInCode", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void DataInCodeAtom<A>::encode() const
+{
+       if ( this->_writer.hasDataInCode ) {
+               uint64_t mhAddress = 0;
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       if ( sect->type() == ld::Section::typeMachHeader )
+                               mhAddress = sect->address;
+                       if ( sect->type() != ld::Section::typeCode )
+                               continue;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               // gather all code-in-data labels
+                               std::vector<const ld::Fixup*> dataInCodeLabels;
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                                       switch ( fit->kind ) {
+                                               case ld::Fixup::kindDataInCodeStartData:
+                                               case ld::Fixup::kindDataInCodeStartJT8:
+                                               case ld::Fixup::kindDataInCodeStartJT16:
+                                               case ld::Fixup::kindDataInCodeStartJT32:
+                                               case ld::Fixup::kindDataInCodeStartJTA32:
+                                               case ld::Fixup::kindDataInCodeEnd:
+                                                       dataInCodeLabels.push_back(fit);
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               // to do: sort labels by address
+                               std::sort(dataInCodeLabels.begin(), dataInCodeLabels.end(), FixupByAddressSorter());
+                               
+                               // convert to array of struct data_in_code_entry
+                               ld::Fixup::Kind prevKind = ld::Fixup::kindDataInCodeEnd;
+                               uint32_t prevOffset = 0;
+                               for ( std::vector<const ld::Fixup*>::iterator sfit = dataInCodeLabels.begin(); sfit != dataInCodeLabels.end(); ++sfit) {
+                                       if ( ((*sfit)->kind != prevKind) && (prevKind != ld::Fixup::kindDataInCodeEnd) ) {
+                                               int len = (*sfit)->offsetInAtom - prevOffset;
+                                               if ( len == 0 )
+                                                       warning("multiple L$start$ labels found at same address in %s at offset 0x%04X", atom->name(), prevOffset);
+                                               this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, (*sfit)->offsetInAtom - prevOffset, prevKind);
+                                       }
+                                       prevKind = (*sfit)->kind;
+                                       prevOffset = (*sfit)->offsetInAtom;
+                               }
+                               if ( prevKind != ld::Fixup::kindDataInCodeEnd ) {
+                                       // add entry if function ends with data
+                                       this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, atom->size() - prevOffset, prevKind);
+                               }
+                       }
+               }
+       }
+       
+       this->_encoded = true;
+}
+
+
+
+
+
+// <rdar://problem/7209249> linker needs to cache "Designated Requirements" in linked binary
+template <typename A>
+class DependentDRAtom : public LinkEditAtom
+{
+public:
+                                                                                               DependentDRAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "dependent dylib DR info"; }
+       // overrides of LinkEditAtom
+       virtual void                                                            encode() const;
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       static ld::Section                      _s_section;
+
+};
+
+template <typename A>
+ld::Section DependentDRAtom<A>::_s_section("__LINKEDIT", "__dependentDR", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void DependentDRAtom<A>::encode() const
+{
+       Security::SuperBlobCore<Security::SuperBlob<Security::kSecCodeMagicDRList>, Security::kSecCodeMagicDRList, uint32_t>::Maker maker;
+       
+       uint32_t index = 0;
+       for(std::vector<ld::dylib::File*>::iterator it=_state.dylibs.begin(); it != _state.dylibs.end(); ++it) {
+               const ld::dylib::File* dylib = *it;
+               Security::BlobCore* dylibDR = (Security::BlobCore*)dylib->codeSignatureDR();
+               void* dup = NULL;
+               if ( dylibDR != NULL ) {
+                       // <rdar://problem/11315321> Maker takes ownership of every blob added
+                       // We need to make a copy here because dylib still owns the pointer returned by codeSignatureDR()
+                       dup = ::malloc(dylibDR->length());
+                       ::memcpy(dup, dylibDR, dylibDR->length());
+               }
+               maker.add(index, (Security::BlobCore*)dup);
+               ++index;
+       }
+       
+       Security::SuperBlob<Security::kSecCodeMagicDRList>* topBlob = maker.make();
+       const uint8_t* data = (uint8_t*)topBlob->data();
+       for(size_t i=0; i < topBlob->length(); ++i)
+               _encodedData.append_byte(data[i]);
+       
+       this->_encoded = true;
+}
+
+
 
 } // namespace tool 
 } // namespace ld 
index 7fbc7550e92751185320fab3a08ffd1f3321f706..172bb4c3cde82d485bde97ef3cc8db9b4421f18d 100644 (file)
@@ -230,6 +230,7 @@ private:
        uint32_t                                                stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
        uint64_t                                                valueForStab(const ld::relocatable::File::Stab& stab);
        uint8_t                                                 sectionIndexForStab(const ld::relocatable::File::Stab& stab);
+       void                                                    addDataInCodeLabels(const ld::Atom* atom, uint32_t& symbolIndex);
        
 
        mutable std::vector<macho_nlist<P> >    _globals;
@@ -242,18 +243,21 @@ private:
        uint32_t                                                                _stabsIndexEnd;
 
        static ld::Section                      _s_section;
+       static int                                      _s_anonNameIndex;
+
 };
 
 template <typename A>
 ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
 
+template <typename A>
+int     SymbolTableAtom<A>::_s_anonNameIndex = 1;
 
 
 template <typename A>
 bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool) 
 {
        macho_nlist<P> entry;
-       static int s_anonNameIndex = 1;
        assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
         
        // set n_strx
@@ -264,7 +268,7 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                        if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
                                // don't use 'l' labels for x86_64 strings
                                // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
-                               sprintf(anonName, "LC%u", s_anonNameIndex++);
+                               sprintf(anonName, "LC%u", _s_anonNameIndex++);
                                symbolName = anonName;
                        }
                }
@@ -279,7 +283,7 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                }
                else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
                        // make auto-strip anonymous name for symbol 
-                       sprintf(anonName, "l%03u", s_anonNameIndex++);
+                       sprintf(anonName, "l%03u", _s_anonNameIndex++);
                        symbolName = anonName;
                }
        }
@@ -335,7 +339,16 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
        macho_nlist<P> entry;
 
        // set n_strx
-       entry.set_n_strx(pool->add(atom->name()));
+       const char* symbolName = atom->name();
+       char anonName[32];
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+                       // make auto-strip anonymous name for symbol 
+                       sprintf(anonName, "l%03u", _s_anonNameIndex++);
+                       symbolName = anonName;
+               }
+       }
+       entry.set_n_strx(pool->add(symbolName));
 
        // set n_type
        if ( atom->definition() == ld::Atom::definitionAbsolute ) {
@@ -356,8 +369,9 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
                                entry.set_n_type(N_EXT | N_SECT | N_PEXT);
                }
                else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
-                                       && (atom->section().type() == ld::Section::typeMachHeader) ) {
-                       // the __mh_execute_header is historical magic and must be an absolute symbol
+                                       && (atom->section().type() == ld::Section::typeMachHeader) 
+                                       && !_options.positionIndependentExecutable() ) {
+                       // the __mh_execute_header is historical magic in non-pie executabls and must be an absolute symbol
                        entry.set_n_type(N_EXT | N_ABS);
                }
        }
@@ -609,6 +623,49 @@ bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos,
        return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
 }
 
+
+template <typename A>
+void SymbolTableAtom<A>::addDataInCodeLabels(const ld::Atom* atom, uint32_t& symbolIndex)
+{
+       char label[64];
+       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+               label[0] = '\0';
+               switch ( fit->kind ) {
+                       case ld::Fixup::kindDataInCodeStartData:
+                               sprintf(label, "L$start$data$%03u", symbolIndex);
+                               break;
+                       case ld::Fixup::kindDataInCodeStartJT8:
+                               sprintf(label, "L$start$jt8$%03u", symbolIndex);
+                               break;
+                       case ld::Fixup::kindDataInCodeStartJT16:
+                               sprintf(label, "L$start$jt16$%03u", symbolIndex);
+                               break;
+                       case ld::Fixup::kindDataInCodeStartJT32:
+                               sprintf(label, "L$start$jt32$%03u", symbolIndex);
+                               break;
+                       case ld::Fixup::kindDataInCodeStartJTA32:
+                               sprintf(label, "L$start$jta32$%03u", symbolIndex);
+                               break;
+                       case ld::Fixup::kindDataInCodeEnd:
+                               sprintf(label, "L$start$code$%03u", symbolIndex);
+                               break;
+                       default:
+                               break;
+               }
+               if ( label[0] != '\0' ) {
+                       macho_nlist<P> entry;
+                       entry.set_n_type(N_SECT);
+                       entry.set_n_sect(atom->machoSection());
+                       entry.set_n_desc(0);
+                       entry.set_n_value(atom->finalAddress() + fit->offsetInAtom);
+                       entry.set_n_strx(this->_writer._stringPoolAtom->add(label));
+                       _locals.push_back(entry);
+                       ++symbolIndex;
+               }
+       }
+}
+
+
 template <typename A>
 void SymbolTableAtom<A>::encode()
 {
@@ -616,6 +673,7 @@ void SymbolTableAtom<A>::encode()
 
        // make nlist entries for all local symbols
        std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+       std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
        _locals.reserve(localAtoms.size()+this->_state.stabs.size());
        this->_writer._localSymbolsStartIndex = 0;
        // make nlist entries for all debug notes
@@ -638,11 +696,19 @@ void SymbolTableAtom<A>::encode()
                if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
                        this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
        }
+       // <rdar://problem/9218847> recreate L$start$ labels in -r mode
+       if ( (_options.outputKind() == Options::kObjectFile) && this->_writer.hasDataInCode ) {
+               for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
+                       this->addDataInCodeLabels(*it, symbolIndex);
+               }
+               for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
+                       this->addDataInCodeLabels(*it, symbolIndex);
+               }
+       }
        this->_writer._localSymbolsCount = symbolIndex;
        
 
        // make nlist entries for all global symbols
-       std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
        _globals.reserve(globalAtoms.size());
        this->_writer._globalSymbolsStartIndex = symbolIndex;
        for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
@@ -919,7 +985,9 @@ uint64_t ExternalRelocationsAtom<A>::size() const
        return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
 }
 
+#if SUPPORT_ARCH_arm_any
 template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+#endif
 template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
 template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
 
@@ -1363,8 +1431,8 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                        }
                        else {
                                // regular pointer
-                               if ( !external && (entry.toAddend != 0) ) {
-                                       // use scattered reloc is target offset is non-zero
+                               if ( !external && (entry.toAddend != 0) && (entry.toTarget->symbolTableInclusion() != ld::Atom::symbolTableNotIn) ) {
+                                       // use scattered reloc if target offset is non-zero into named atom (5658046)
                                        sreloc1->set_r_scattered(true);
                                        sreloc1->set_r_pcrel(false);
                                        sreloc1->set_r_length(2);
@@ -1390,6 +1458,7 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
 }
 
 
+#if SUPPORT_ARCH_arm_any
 template <>
 void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
                                                                                                        const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
@@ -1614,6 +1683,7 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                
        }
 }
+#endif
 
 
 
@@ -1866,14 +1936,18 @@ bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
 template <typename A>
 void IndirectSymbolTableAtom<A>::encode()
 {
-       // static executables should not have an indirect symbol table
-       if ( this->_options.outputKind() == Options::kStaticExecutable ) 
+       // static executables should not have an indirect symbol table, unless PIE
+       if ( (this->_options.outputKind() == Options::kStaticExecutable) && !_options.positionIndependentExecutable() ) 
                return;
 
        // x86_64 kext bundles should not have an indirect symbol table
        if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() ) 
                return;
 
+       // slidable static executables (-static -pie) should not have an indirect symbol table
+       if ( (this->_options.outputKind() == Options::kStaticExecutable) && this->_options.positionIndependentExecutable() ) 
+               return;
+
        // find all special sections that need a range of the indirect symbol table section
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
index 629903f89a082f5b3cc51e1c726156da9f1f0a99..58d49a74ad63973bd81aecb586ed79928239a4c2 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <mach/vm_prot.h>
+#include <sys/sysctl.h>
 #include <mach-o/dyld.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <spawn.h>
+#include <cxxabi.h>
+#include <Availability.h>
 
 #include <vector>
 
-#include "configure.h"
 #include "Options.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
+#include "Snapshot.h"
 
 // upward dependency on lto::version()
 namespace lto {
@@ -43,9 +49,19 @@ namespace lto {
 
 // magic to place command line in crash reports
 const int crashreporterBufferSize = 2000;
-extern "C" char* __crashreporter_info__;
 static char crashreporterBuffer[crashreporterBufferSize];
-char* __crashreporter_info__ = crashreporterBuffer;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+       #include <CrashReporterClient.h>
+       // hack until ld does not need to build on 10.6 anymore
+    struct crashreporter_annotations_t gCRAnnotations 
+        __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) 
+        = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
+#else
+       extern "C" char* __crashreporter_info__;
+       __attribute__((used)) 
+       char* __crashreporter_info__ = crashreporterBuffer;
+#endif
+
 
 static bool                    sEmitWarnings = true;
 static bool                    sFatalWarnings = false;
@@ -88,6 +104,19 @@ void throwf(const char* format, ...)
        throw t;
 }
 
+bool Options::FileInfo::checkFileExists(const char *p)
+{
+       struct stat statBuffer;
+       if (p == NULL) p = path;
+       if ( stat(p, &statBuffer) == 0 ) {
+               if (p != path) path = strdup(p);
+               fileLen = statBuffer.st_size;
+               modTime = statBuffer.st_mtime;
+               return true;
+       }
+    return false;
+}
+
 Options::Options(int argc, const char* argv[])
        : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), 
          fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
@@ -102,8 +131,8 @@ Options::Options(int argc, const char* argv[])
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
          fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
-         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), 
-         fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fExecutableStack(false), 
+         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), 
+         fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
          fCommonsMode(kCommonsIgnoreDylibs),  fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), 
@@ -112,7 +141,7 @@ Options::Options(int argc, const char* argv[])
          fSharedRegionEligible(false), fPrintOrderFileStatistics(false),  
          fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
          fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
-         fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), 
+         fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
          fUsingLazyDylibLinking(false), fEncryptable(true), 
          fOrderData(true), fMarkDeadStrippableDylib(false),
          fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
@@ -131,10 +160,16 @@ Options::Options(int argc, const char* argv[])
          fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), 
          fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
          fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
+         fDataInCodeInfoLoadCommand(false),
          fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false), 
+         fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
+         fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
+         fSourceVersionLoadCommand(false), 
+         fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
+         fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
-         fSaveTempFiles(false)
+         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -148,7 +183,6 @@ Options::~Options()
 {
 }
 
-
 bool Options::errorBecauseOfWarnings() const
 {
        return (sFatalWarnings && (sWarningsCount > 0));
@@ -479,114 +513,77 @@ bool Options::keepLocalSymbol(const char* symbolName) const
 
 void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
 {
-       fArchitecture = type;
-       fSubArchitecture = subtype;
-       switch ( type ) {
-       case CPU_TYPE_I386:
-               fArchitectureName = "i386";
-               if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
-       #ifdef DEFAULT_MACOSX_MIN_VERSION
-                       warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                       setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
-       #else
-                       warning("-macosx_version_min not specificed, assuming 10.6");
-                       fMacVersionMin = ld::mac10_6;
-       #endif          
-               }
-               if ( !fMakeCompressedDyldInfo && (fMacVersionMin >= ld::mac10_6) && !fMakeCompressedDyldInfoForceOff )
-                       fMakeCompressedDyldInfo = true;
-               break;
-       case CPU_TYPE_X86_64:
-               fArchitectureName = "x86_64";
-               if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
-       #ifdef DEFAULT_MACOSX_MIN_VERSION
-                       warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                       setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
-       #else
-                       warning("-macosx_version_min not specificed, assuming 10.6");
-                       fMacVersionMin = ld::mac10_6;
-       #endif          
-               }
-               if ( !fMakeCompressedDyldInfo && (fMacVersionMin >= ld::mac10_6) && !fMakeCompressedDyldInfoForceOff )
-                       fMakeCompressedDyldInfo = true;
-               break;
-       case CPU_TYPE_ARM:
-               fHasPreferredSubType = true;
-               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                       if ( t->subType == subtype ) {
-                               fArchitectureName = t->subTypeName;
-                               fArchSupportsThumb2 = t->supportsThumb2;
-                               break;
+       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+               if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
+                       fArchitecture = type;
+                       fSubArchitecture = subtype;
+                       fArchitectureName = t->archName;
+                       fHasPreferredSubType = t->isSubType;
+                       fArchSupportsThumb2 = t->supportsThumb2;
+                       switch ( type ) {
+                               case CPU_TYPE_I386:
+                               case CPU_TYPE_X86_64:
+                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                               #ifdef DEFAULT_MACOSX_MIN_VERSION
+                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                               #else
+                                               warning("-macosx_version_min not specified, assuming 10.6");
+                                               fMacVersionMin = ld::mac10_6;
+                               #endif          
+                                       }
+                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+                                               fMakeCompressedDyldInfo = true;
+                                       break;
+                               case CPU_TYPE_ARM:
+                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                               #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
+                                               warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                               #elif defined(DEFAULT_MACOSX_MIN_VERSION)
+                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
+                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                               #else
+                                               warning("-macosx_version_min not specified, assuming 10.6");
+                                               fMacVersionMin = ld::mac10_6;
+                               #endif
+                                       }
+                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+                                               fMakeCompressedDyldInfo = true;
+                                       break;
                        }
+                       fLinkSnapshot.recordArch(fArchitectureName);
+                       return;
                }
-               assert(fArchitectureName != NULL);
-               if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
-#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
-                       warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                       setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
-#elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                       warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                       setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
-#else
-                       warning("-macosx_version_min not specificed, assuming 10.6");
-                       fMacVersionMin = ld::mac10_6;
-#endif
-               }
-               if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
-                       fMakeCompressedDyldInfo = true;
-               break;
-       default:
-               fArchitectureName = "unknown architecture";
-               break;
        }
+       fArchitectureName = "unknown architecture";
 }
 
 void Options::parseArch(const char* arch)
 {
        if ( arch == NULL )
                throw "-arch must be followed by an architecture string";
-       fArchitectureName = arch;
-       if ( strcmp(arch, "i386") == 0 ) {
-               fArchitecture = CPU_TYPE_I386;
-               fSubArchitecture = CPU_SUBTYPE_I386_ALL;
-       }
-       else if ( strcmp(arch, "x86_64") == 0 ) {
-               fArchitecture = CPU_TYPE_X86_64;
-               fSubArchitecture = CPU_SUBTYPE_X86_64_ALL;
-       }
-       else if ( strcmp(arch, "arm") == 0 ) {
-               fArchitecture = CPU_TYPE_ARM;
-               fSubArchitecture = CPU_SUBTYPE_ARM_ALL;
-       }
-       else {
-               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                       if ( strcmp(t->subTypeName,arch) == 0 ) {
-                               fArchitecture = CPU_TYPE_ARM;
-                               fSubArchitecture = t->subType;
-                               fArchSupportsThumb2 = t->supportsThumb2;
-                               fHasPreferredSubType = true;
-                               return;
-                       }
+       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+               if ( strcmp(t->archName,arch) == 0 ) {
+                       fArchitectureName = arch;
+                       fArchitecture = t->cpuType;
+                       fSubArchitecture = t->cpuSubType;
+                       fHasPreferredSubType = t->isSubType;
+                       fArchSupportsThumb2 = t->supportsThumb2;
+                       return;
                }
-               throwf("unknown/unsupported architecture name for: -arch %s", arch);
        }
+       throwf("unknown/unsupported architecture name for: -arch %s", arch);
 }
 
 bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) const
 {
-       struct stat statBuffer;
        char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
        sprintf(possiblePath, format,  dir, rootName);
-       bool found = (stat(possiblePath, &statBuffer) == 0);
+       bool found = result.checkFileExists(possiblePath);
        if ( fTraceDylibSearching )
                printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
-       if ( found ) {
-               result.path = strdup(possiblePath);
-               result.fileLen = statBuffer.st_size;
-               result.modTime = statBuffer.st_mtime;
-               return true;
-       }
-       return false;
+       return found;
 }
 
 
@@ -674,7 +671,6 @@ Options::FileInfo Options::findFramework(const char* frameworkName)
 
 Options::FileInfo Options::findFramework(const char* rootName, const char* suffix)
 {
-       struct stat statBuffer;
        for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
                 it != fFrameworkSearchPaths.end();
                 it++) {
@@ -695,15 +691,12 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                                strcat(possiblePath, suffix);
                        }
                }
-               bool found = (stat(possiblePath, &statBuffer) == 0);
+        FileInfo result;
+               bool found = result.checkFileExists(possiblePath);
                if ( fTraceDylibSearching )
                        printf("[Logging for XBS]%sfound framework: '%s'\n",
                                   (found ? " " : " not "), possiblePath);
                if ( found ) {
-                       FileInfo result;
-                       result.path = strdup(possiblePath);
-                       result.fileLen = statBuffer.st_size;
-                       result.modTime = statBuffer.st_mtime;
                        return result;
                }
        }
@@ -717,7 +710,6 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
 Options::FileInfo Options::findFile(const char* path) const
 {
        FileInfo result;
-       struct stat statBuffer;
 
        // if absolute path and not a .o file, the use SDK prefix
        if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
@@ -731,19 +723,13 @@ Options::FileInfo Options::findFile(const char* path) const
                        if ( possiblePath[sdkPathDirLen-1] == '/' )
                                possiblePath[sdkPathDirLen-1] = '\0';
                        strcat(possiblePath, path);
-                       if ( stat(possiblePath, &statBuffer) == 0 ) {
-                               result.path = strdup(possiblePath);
-                               result.fileLen = statBuffer.st_size;
-                               result.modTime = statBuffer.st_mtime;
+                       if ( result.checkFileExists(possiblePath) ) {
                                return result;
                        }
                }
        }
        // try raw path
-       if ( stat(path, &statBuffer) == 0 ) {
-               result.path = strdup(path);
-               result.fileLen = statBuffer.st_size;
-               result.modTime = statBuffer.st_mtime;
+       if ( result.checkFileExists(path) ) {
                return result;
        }
 
@@ -756,10 +742,7 @@ Options::FileInfo Options::findFile(const char* path) const
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
-               if ( stat(newPath, &statBuffer) == 0 ) {
-                       result.path = strdup(newPath);
-                       result.fileLen = statBuffer.st_size;
-                       result.modTime = statBuffer.st_mtime;
+               if ( result.checkFileExists(newPath) ) {
                        return result;
                }
        }
@@ -885,7 +868,7 @@ void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
        fclose(file);
 }
 
-void Options::loadFileList(const char* fileOfPaths)
+void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal)
 {
        FILE* file;
        const char* comma = strrchr(fileOfPaths, ',');
@@ -901,16 +884,17 @@ void Options::loadFileList(const char* fileOfPaths)
                        realFileOfPaths[realFileOfPathsLen] = '\0';
                        file = fopen(realFileOfPaths, "r");
                        if ( file == NULL )
-                               throwf("-filelist file not found: %s\n", realFileOfPaths);
+                               throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno));
                }
        }
        else {
                file = fopen(fileOfPaths, "r");
                if ( file == NULL )
-                       throwf("-filelist file not found: %s\n", fileOfPaths);
+                       throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno));
        }
 
        char path[PATH_MAX];
+       ld::File::Ordinal previousOrdinal = baseOrdinal;
        while ( fgets(path, PATH_MAX, file) != NULL ) {
                path[PATH_MAX-1] = '\0';
                char* eol = strchr(path, '\n');
@@ -921,10 +905,34 @@ void Options::loadFileList(const char* fileOfPaths)
                        strcpy(builtPath, prefix);
                        strcat(builtPath, "/");
                        strcat(builtPath, path);
-                       fInputFiles.push_back(findFile(builtPath));
+           if (fPipelineFifo != NULL) {
+                          FileInfo info = FileInfo(builtPath);
+                          info.ordinal = previousOrdinal.nextFileListOrdinal();
+                          previousOrdinal = info.ordinal;
+                          info.fromFileList = true;
+              fInputFiles.push_back(info);
+           } else {
+                          FileInfo info = findFile(builtPath);
+                          info.ordinal = previousOrdinal.nextFileListOrdinal();
+                          previousOrdinal = info.ordinal;
+                          info.fromFileList = true;
+                          fInputFiles.push_back(info);
+           }
                }
                else {
-                       fInputFiles.push_back(findFile(path));
+           if (fPipelineFifo != NULL) {
+                          FileInfo info = FileInfo(path);
+                          info.ordinal = previousOrdinal.nextFileListOrdinal();
+                          previousOrdinal = info.ordinal;
+                          info.fromFileList = true;
+                          fInputFiles.push_back(info);
+           } else {
+                          FileInfo info = findFile(path);
+                          info.ordinal = previousOrdinal.nextFileListOrdinal();
+                          previousOrdinal = info.ordinal;
+                          info.fromFileList = true;
+                          fInputFiles.push_back(info);
+           }
                }
        }
        fclose(file);
@@ -1719,6 +1727,9 @@ void Options::warnObsolete(const char* arg)
 //
 void Options::parse(int argc, const char* argv[])
 {
+    // Store the original args in the link snapshot.
+    fLinkSnapshot.recordRawArgs(argc, argv);
+    
        // pass one builds search list from -L and -F options
        this->buildSearchPaths(argc, argv);
 
@@ -1730,12 +1741,17 @@ void Options::parse(int argc, const char* argv[])
                const char* arg = argv[i];
 
                if ( arg[0] == '-' ) {
+            // by default, copy one arg to the snapshot link command, and do no file copying
+            int snapshotArgIndex = i;
+            int snapshotArgCount = -1; // -1 means compute count based on change in index
+            int snapshotFileArgIndex = -1; // -1 means no data file parameter to arg
 
                        // Since we don't care about the files passed, just the option names, we do this here.
                        if (fPrintOptions)
                                fprintf (stderr, "[Logging ld64 options]\t%s\n", arg);
 
                        if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
+                snapshotArgCount = 0; // stripped out of link snapshot
                                if (arg[2] == '\0')
                                        ++i;
                                // previously handled by buildSearchPaths()
@@ -1782,22 +1798,38 @@ void Options::parse(int argc, const char* argv[])
                                fOutputKind = kKextBundle;
                        }
                        else if ( strcmp(arg, "-o") == 0 ) {
+                snapshotArgCount = 0;
                                fOutputFile = argv[++i];
+                fLinkSnapshot.setSnapshotName(fOutputFile);
                        }
                        else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
+                snapshotArgCount = 0;
                                FileInfo info = findLibrary(&arg[7], true);
                                info.options.fLazyLoad = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                        }
+                       else if ( strcmp(arg, "-lto_library") == 0 ) {
+                snapshotFileArgIndex = 1;
+                               fOverridePathlibLTO = argv[++i];
+                               if ( fOverridePathlibLTO == NULL )
+                                       throw "missing argument to -lto_library";
+                       }
                        else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) {
-                               addLibrary(findLibrary(&arg[2]));
+                snapshotArgCount = 0;
+                               FileInfo info = findLibrary(&arg[2]);
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+                               addLibrary(info);
                        }
                        // This causes a dylib to be weakly bound at
                        // link time.  This corresponds to weak_import.
                        else if ( strncmp(arg, "-weak-l", 7) == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findLibrary(&arg[7]);
                                info.options.fWeakImport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        // Avoid lazy binding.
@@ -1831,6 +1863,7 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-force_load") == 0 ) {
                                FileInfo info = findFile(argv[++i]);
                                info.options.fForceLoad = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        // Library versioning.
@@ -1851,10 +1884,12 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-sectorder") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
                                        throw "-sectorder missing <segment> <section> <file-path>";
+                snapshotFileArgIndex = 3;
                                parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                        }
                        else if ( strcmp(arg, "-order_file") == 0 ) {
+                snapshotFileArgIndex = 1;
                                parseOrderFile(argv[++i], false);
                        }
                        else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
@@ -1865,6 +1900,7 @@ void Options::parse(int argc, const char* argv[])
                        else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
                                        throw "-sectcreate missing <segment> <section> <file-path>";
+                snapshotFileArgIndex = 3;
                                addSection(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                        }
@@ -1873,7 +1909,7 @@ void Options::parse(int argc, const char* argv[])
                                          || (strcmp(arg, "-dylinker_install_name") == 0)
                                          || (strcmp(arg, "-install_name") == 0)) {
                                fDylibInstallName = argv[++i];
-                                if ( fDylibInstallName == NULL )
+                if ( fDylibInstallName == NULL )
                                        throw "-install_name missing <path>";
                        }
                        // Sets the base address of the output.
@@ -1893,10 +1929,12 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Same as -@ from the FSF linker.
                        else if ( strcmp(arg, "-filelist") == 0 ) {
+                 snapshotArgCount = 0;
                                 const char* path = argv[++i];
                                 if ( (path == NULL) || (path[0] == '-') )
                                        throw "-filelist missing <path>";
-                                loadFileList(path);
+                                ld::File::Ordinal baseOrdinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+                                loadFileList(path, baseOrdinal);
                        }
                        else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
                                 fKeepPrivateExterns = true;
@@ -1918,6 +1956,7 @@ void Options::parse(int argc, const char* argv[])
                                }
                        }
                        else if ( strcmp(arg, "-interposable_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                fInterposeMode = kInterposeSome;
                                loadExportFile(argv[++i], "-interposable_list", fInterposeList);
                        }
@@ -1926,12 +1965,14 @@ void Options::parse(int argc, const char* argv[])
                                fInterposeMode = kInterposeNone;
                        }
                        else if ( strcmp(arg, "-exported_symbols_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                if ( fExportMode == kDontExportSome )
                                        throw "can't use -exported_symbols_list and -unexported_symbols_list";
                                fExportMode = kExportSome;
                                loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols);
                        }
                        else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                if ( fExportMode == kExportSome )
                                        throw "can't use -unexported_symbols_list and -exported_symbols_list";
                                fExportMode = kDontExportSome;
@@ -1950,12 +1991,14 @@ void Options::parse(int argc, const char* argv[])
                                fDontExportSymbols.insert(argv[++i]);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                if ( fLocalSymbolHandling == kLocalSymbolsSelectiveExclude )
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveInclude;
                                loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                if ( fLocalSymbolHandling == kLocalSymbolsSelectiveInclude )
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveExclude;
@@ -1971,27 +2014,42 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Similar to -weak-l but uses the absolute path name to the library.
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFile(argv[++i]);
                                info.options.fWeakImport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-lazy_library") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFile(argv[++i]);
                                info.options.fLazyLoad = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                        }
                        else if ( strcmp(arg, "-framework") == 0 ) {
-                               addLibrary(findFramework(argv[++i]));
+                snapshotArgCount = 0;
+                               FileInfo info = findFramework(argv[++i]);
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
+                               addLibrary(info);
                        }
                        else if ( strcmp(arg, "-weak_framework") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFramework(argv[++i]);
                                info.options.fWeakImport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-lazy_framework") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFramework(argv[++i]);
                                info.options.fLazyLoad = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                        }
@@ -2002,7 +2060,7 @@ void Options::parse(int argc, const char* argv[])
                                // previously handled by buildSearchPaths()
                        }
                        else if ( strcmp(arg, "-undefined") == 0 ) {
-                                setUndefinedTreatment(argv[++i]);
+                setUndefinedTreatment(argv[++i]);
                        }
                        // Debugging output flag.
                        else if ( strcmp(arg, "-arch_multiple") == 0 ) {
@@ -2038,7 +2096,7 @@ void Options::parse(int argc, const char* argv[])
                        // Warn, error or make strong a mismatch between weak
                        // and non-weak references.
                        else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
-                                setWeakReferenceMismatchTreatment(argv[++i]);
+                setWeakReferenceMismatchTreatment(argv[++i]);
                        }
                        // For a deployment target of 10.3 and earlier ld64 will
                        // prebind an executable with 0s in all addresses that
@@ -2066,6 +2124,8 @@ void Options::parse(int argc, const char* argv[])
                        // This should probably be deprecated when we respect -L and -F
                        // when searching for libraries.
                        else if ( strcmp(arg, "-dylib_file") == 0 ) {
+                // ignore for snapshot because a stub dylib will be created in the snapshot
+                 snapshotArgCount = 0;
                                 addDylibOverride(argv[++i]);
                        }
                        // What to expand @executable_path to if found in dependent dylibs
@@ -2122,6 +2182,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+                snapshotFileArgIndex = 1;
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-seg_addr_table missing argument";
@@ -2185,10 +2246,12 @@ void Options::parse(int argc, const char* argv[])
                                i += 2;
                        }
                        else if ( strcmp(arg, "-bundle_loader") == 0 ) {
+                snapshotFileArgIndex = 1;
                                fBundleLoader = argv[++i];
                                if ( (fBundleLoader == NULL) || (fBundleLoader[0] == '-') )
                                        throw "-bundle_loader missing <path>";
                                FileInfo info = findFile(fBundleLoader);
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                info.options.fBundleLoader = true;
                                fInputFiles.push_back(info);
                        }
@@ -2394,6 +2457,7 @@ void Options::parse(int argc, const char* argv[])
                                // previously handled by buildSearchPaths()
                        }
                        else if ( strcmp(arg, "-syslibroot") == 0 ) {
+                snapshotArgCount = 0;
                                ++i;
                                // previously handled by buildSearchPaths()
                        }
@@ -2404,6 +2468,7 @@ void Options::parse(int argc, const char* argv[])
                                fUUIDMode = kUUIDRandom;
                        }
                        else if ( strcmp(arg, "-dtrace") == 0 ) {
+                snapshotFileArgIndex = 1;
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-dtrace missing argument";
@@ -2426,6 +2491,7 @@ void Options::parse(int argc, const char* argv[])
                                fAliases.push_back(pair);
                        }
                        else if ( strcmp(arg, "-alias_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                parseAliasFile(argv[++i]);
                        }
                        // put this last so that it does not interfer with other options starting with 'i'
@@ -2468,33 +2534,51 @@ void Options::parse(int argc, const char* argv[])
                                fDisablePositionIndependentExecutable = true;
                        }
                        else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findLibrary(&arg[11], true);
                                info.options.fReExport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-reexport_library") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFile(argv[++i]);
                                info.options.fReExport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-reexport_framework") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFramework(argv[++i]);
                                info.options.fReExport = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findLibrary(&arg[9], true);
                                info.options.fUpward = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-upward_library") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFile(argv[++i]);
                                info.options.fUpward = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-upward_framework") == 0 ) {
+                // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
+                snapshotArgCount = 0;
                                FileInfo info = findFramework(argv[++i]);
                                info.options.fUpward = true;
+                               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                        }
                        else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
@@ -2539,6 +2623,7 @@ void Options::parse(int argc, const char* argv[])
                                fMarkDeadStrippableDylib = true;
                        }
                        else if ( strcmp(arg, "-exported_symbols_order") == 0 ) {
+                snapshotFileArgIndex = 1;
                                loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
                        }
                        else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
@@ -2613,6 +2698,12 @@ void Options::parse(int argc, const char* argv[])
                                fFunctionStartsForcedOff = true;
                                fFunctionStartsForcedOn = false;
                        }
+                       else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
+                               fDataInCodeInfoLoadCommand = false;
+                       }
+                       else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
+                               fDataInCodeInfoLoadCommand = true;
+                       }
                        else if ( strcmp(arg, "-object_path_lto") == 0 ) {
                                fTempLtoObjectPath = argv[++i];
                                if ( fTempLtoObjectPath == NULL )
@@ -2622,9 +2713,11 @@ void Options::parse(int argc, const char* argv[])
                                fObjcCategoryMerging = false;
                        }
                        else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
                        }
                        else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
                        }
                        else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
@@ -2640,6 +2733,7 @@ void Options::parse(int argc, const char* argv[])
                                fForceNotWeakSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
+                snapshotFileArgIndex = 1;
                                if ( fExportMode == kExportSome )
                                        throw "can't use -exported_symbols_list and -reexported_symbols_list";
                                loadExportFile(argv[++i], "-reexported_symbols_list", fReExportSymbols);
@@ -2654,13 +2748,56 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
                                fPageAlignDataAtoms = true;
+                       } 
+                       else if (strcmp(arg, "-debug_snapshot") == 0) {
+                fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+                fSnapshotRequested = true;
+            }
+                       else if ( strcmp(arg, "-new_main") == 0 ) {
+                               fEntryPointLoadCommandForceOn = true;
+                       }
+                       else if ( strcmp(arg, "-no_new_main") == 0 ) {
+                               fEntryPointLoadCommandForceOff = true;
+                       }
+                       else if ( strcmp(arg, "-source_version") == 0 ) {
+                                const char* vers = argv[++i];
+                                if ( vers == NULL )
+                                       throw "-source_version missing <version>";
+                               fSourceVersion = parseVersionNumber64(vers);
+                       }
+                       else if ( strcmp(arg, "-add_source_version") == 0 ) {
+                               fSourceVersionLoadCommandForceOn = true;
+                       }
+                       else if ( strcmp(arg, "-no_source_version") == 0 ) {
+                               fSourceVersionLoadCommandForceOff = true;
+                       }
+                       else if ( strcmp(arg, "-sdk_version") == 0 ) {
+                                const char* vers = argv[++i];
+                                if ( vers == NULL )
+                                       throw "-sdk_version missing <version>";
+                               fSDKVersion = parseVersionNumber32(vers);
+                       }
+                       else if ( strcmp(arg, "-dependent_dr_info") == 0 ) {
+                               fDependentDRInfoForcedOn = true;
+                       }
+                       else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) {
+                               fDependentDRInfoForcedOff = true;
+                       }
+                       else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
+                               fKextsUseStubs = true;
                        }
                        else {
                                throwf("unknown option: %s", arg);
                        }
+            
+            if (snapshotArgCount == -1)
+                snapshotArgCount = i-snapshotArgIndex+1;
+            if (snapshotArgCount > 0)
+                fLinkSnapshot.addSnapshotLinkArg(snapshotArgIndex, snapshotArgCount, snapshotFileArgIndex);
                }
                else {
                        FileInfo info = findFile(arg);
+                       info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                        if ( strcmp(&info.path[strlen(info.path)-2], ".a") == 0 )
                                addLibrary(info);
                        else
@@ -2670,8 +2807,13 @@ void Options::parse(int argc, const char* argv[])
        
        // if a -lazy option was used, implicitly link in lazydylib1.o
        if ( fUsingLazyDylibLinking ) {
-               addLibrary(findLibrary("lazydylib1.o"));
+               FileInfo info = findLibrary("lazydylib1.o");
+               info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)argc);
+               addLibrary(info);
        }
+    
+    if (fSnapshotRequested)
+        fLinkSnapshot.createSnapshot();
 }
 
 
@@ -2746,11 +2888,12 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        fVerbose = true;
                        extern const char ldVersionString[];
                        fprintf(stderr, "%s", ldVersionString);
+                       fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS);
                         // if only -v specified, exit cleanly
                         if ( argc == 2 ) {
                                const char* ltoVers = lto::version();
                                if ( ltoVers != NULL )
-                                       fprintf(stderr, "%s\n", ltoVers);
+                                       fprintf(stderr, "LTO support using: %s\n", ltoVers);
                                exit(0);
                        }
                }
@@ -2924,6 +3067,19 @@ void Options::parsePreCommandLineEnvironmentSettings()
        const char* customDyldPath = getenv("LD_DYLD_PATH");
        if ( customDyldPath != NULL ) 
                fDyldInstallPath = customDyldPath;
+    
+    const char* debugArchivePath = getenv("LD_DEBUG_SNAPSHOT");
+    if (debugArchivePath != NULL) {
+        fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+        if (strlen(debugArchivePath) > 0)
+            fLinkSnapshot.setSnapshotPath(debugArchivePath);
+        fSnapshotRequested = true;
+    }
+
+    const char* pipeFdString = getenv("LD_PIPELINE_FIFO");
+    if (pipeFdString != NULL) {
+               fPipelineFifo = pipeFdString;
+    }
 }
 
 
@@ -2966,6 +3122,13 @@ void Options::parsePostCommandLineEnvironmentSettings()
        // allow build system to force on -warn_commons
        if ( getenv("LD_WARN_COMMONS") != NULL )
                fWarnCommons = true;
+       
+       // allow B&I to set default -source_version
+       if ( fSourceVersion == 0 ) {
+               const char* vers = getenv("RC_ProjectSourceVersion");
+               if ( vers != NULL )
+                       fSourceVersion = parseVersionNumber64(vers);
+       }
                
 }
 
@@ -3019,10 +3182,10 @@ void Options::reconfigureDefaults()
                                case CPU_TYPE_X86_64:
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #ifdef DEFAULT_MACOSX_MIN_VERSION
-                                               warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
+                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #else
-                                               warning("-macosx_version_min not specificed, assuming 10.6");
+                                               warning("-macosx_version_min not specified, assuming 10.6");
                                                fMacVersionMin = ld::mac10_6;
                        #endif          
                                        }
@@ -3030,13 +3193,13 @@ void Options::reconfigureDefaults()
                                case CPU_TYPE_ARM:
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
-                                               warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+                                               warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                        #elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                                               warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION);
+                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #else
-                                               warning("-macosx_version_min not specificed, assuming 10.6");
+                                               warning("-macosx_version_min not specified, assuming 10.6");
                                                fMacVersionMin = ld::mac10_6;
                        #endif
                                        }
@@ -3058,7 +3221,7 @@ void Options::reconfigureDefaults()
                        }
                        break;
                case CPU_TYPE_X86_64:
-                       if ( fMacVersionMin < ld::mac10_4 ) {
+                       if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
                                //warning("-macosx_version_min should be 10.4 or later for x86_64");
                                fMacVersionMin = ld::mac10_4;
                        }
@@ -3080,7 +3243,8 @@ void Options::reconfigureDefaults()
                     // iOS 5.0 and later use new MH_KEXT_BUNDLE type
                     fMakeCompressedDyldInfo = false;
                     fMakeCompressedDyldInfoForceOff = true;
-                    fAllowTextRelocs = true;
+                    fAllowTextRelocs = true; 
+                                       fKextsUseStubs = !fAllowTextRelocs;
                     fUndefinedTreatment = kUndefinedDynamicLookup;
                                        break;
                                }
@@ -3357,27 +3521,14 @@ void Options::reconfigureDefaults()
 
        
        // only use compressed LINKEDIT for:
-       //                      x86_64 and i386 on Mac OS X 10.6 or later
-       //                      arm on iPhoneOS 3.1 or later
+       //                      Mac OS X 10.6 or later
+       //                      iOS 3.1 or later
        if ( fMakeCompressedDyldInfo ) {
-               switch (fArchitecture) {
-                       case CPU_TYPE_I386:
-                               if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator always uses compressed LINKEDIT
-                                       break;
-                       case CPU_TYPE_X86_64:
-                               if ( fMacVersionMin < ld::mac10_6 ) 
-                                       fMakeCompressedDyldInfo = false;
-                               break;
-            case CPU_TYPE_ARM:
-                               if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
-                                       fMakeCompressedDyldInfo = false;
-                               break;
-                       default:
-                               fMakeCompressedDyldInfo = false;
-               }
+               if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
+                       fMakeCompressedDyldInfo = false;
        }
 
-               
+
        // only ARM enforces that cpu-sub-types must match
        if ( fArchitecture != CPU_TYPE_ARM )
                fAllowCpuSubtypeMismatches = true;
@@ -3437,9 +3588,9 @@ void Options::reconfigureDefaults()
        // set fOutputSlidable
        switch ( fOutputKind ) {
                case Options::kObjectFile:
-               case Options::kStaticExecutable:
                        fOutputSlidable = false;
                        break;
+               case Options::kStaticExecutable:
                case Options::kDynamicExecutable:
                        fOutputSlidable = fPositionIndependentExecutable;
                        break;
@@ -3490,10 +3641,12 @@ void Options::reconfigureDefaults()
        switch ( fOutputKind ) {
                case Options::kObjectFile:
                        fFunctionStartsLoadCommand = false;
+                       fDataInCodeInfoLoadCommand = false;
                        break;
                case Options::kPreload:
                case Options::kStaticExecutable:
                case Options::kKextBundle:
+                       fDataInCodeInfoLoadCommand = false;
                        if ( fFunctionStartsForcedOn )
                                fFunctionStartsLoadCommand = true;
                        break;
@@ -3530,6 +3683,130 @@ void Options::reconfigureDefaults()
        // on the command line
        if ( (fArchitecture == CPU_TYPE_I386) && (fOutputKind == kDynamicExecutable) && !fDisableNonExecutableHeap)
                fNonExecutableHeap = true;
+               
+       // Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+                       if ( fEntryPointLoadCommandForceOn ) {
+                               fEntryPointLoadCommand = true;
+                               fEntryName = "_main";
+                       }
+                       else if ( fEntryPointLoadCommandForceOff ) {
+                               fNeedsThreadLoadCommand = true;
+                       }
+                       else {
+                               if ( minOS(ld::mac10_8, ld::iOS_Future) ) {
+                                       fEntryPointLoadCommand = true;
+                                       fEntryName = "_main";
+                               }
+                               else
+                                       fNeedsThreadLoadCommand = true;
+                       }
+                       break;
+               case Options::kObjectFile:
+               case Options::kKextBundle:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       break;
+                       
+               case Options::kStaticExecutable:
+               case Options::kPreload:
+               case Options::kDyld:
+                       fNeedsThreadLoadCommand = true;
+                       break;
+       }
+       
+       // add LC_SOURCE_VERSION
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kKextBundle:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+               case Options::kStaticExecutable:
+                       if ( fSourceVersionLoadCommandForceOn ) {
+                               fSourceVersionLoadCommand = true;
+                       }
+                       else if ( fSourceVersionLoadCommandForceOff ) {
+                               fSourceVersionLoadCommand = false;
+                       }
+                       else {
+                               if ( minOS(ld::mac10_8, ld::iOS_Future) ) {
+                                       fSourceVersionLoadCommand = true;
+                               }
+                               else
+                                       fSourceVersionLoadCommand = false;
+                       }
+                       break;
+               case Options::kObjectFile:
+               case Options::kPreload:
+                       fSourceVersionLoadCommand = false;
+                       break;
+       }
+       
+       
+       // add LC_DYLIB_CODE_SIGN_DRS
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       if ( fDependentDRInfoForcedOn ) {
+                               fDependentDRInfo = true;
+                       }
+                       else if ( fDependentDRInfoForcedOff ) {
+                               fDependentDRInfo = false;
+                       }
+                       else {
+                               if ( minOS(ld::mac10_8, ld::iOS_Future) ) 
+                                       fDependentDRInfo = true;
+                               else
+                                       fDependentDRInfo = false;
+                       }
+                       break;
+               case Options::kKextBundle:
+               case Options::kDyld:
+               case Options::kStaticExecutable:
+               case Options::kObjectFile:
+               case Options::kPreload:
+                       fDependentDRInfo = false;
+                       break;
+       }
+       
+       // if -sdk_version not on command line, infer from -syslibroot
+       if ( (fSDKVersion == 0) && (fSDKPaths.size() > 0) ) {
+               const char* sdkPath = fSDKPaths.front();
+               const char* end = &sdkPath[strlen(sdkPath)-1];
+               while ( !isdigit(*end) && (end > sdkPath) )
+                       --end;
+               const char* start = end-1;
+               while ( (isdigit(*start) || (*start == '.')) && (start > sdkPath))
+                       --start;
+               char sdkVersionStr[32];
+               int len = end-start+1;
+               if ( len > 2 ) {
+                       strlcpy(sdkVersionStr, start+1, len);
+                       fSDKVersion = parseVersionNumber32(sdkVersionStr);
+               }
+       }
+       
+       // if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version
+       if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) {
+               // special case if RC_ProjectName and MACOSX_DEPLOYMENT_TARGET are both set that sdkversion=minos
+               if ( getenv("RC_ProjectName") && getenv("MACOSX_DEPLOYMENT_TARGET") ) {
+                       fSDKVersion = fMacVersionMin;
+               }
+               else {
+                       int mib[2] = { CTL_KERN, KERN_OSRELEASE };
+                       char kernVersStr[100];
+                       size_t strlen = sizeof(kernVersStr);
+                       if ( sysctl(mib, 2, kernVersStr, &strlen, NULL, 0) != -1 ) {
+                               uint32_t kernVers = parseVersionNumber32(kernVersStr);
+                               int minor = (kernVers >> 16) - 4;  // kernel major version is 4 ahead of x in 10.x
+                               fSDKVersion = 0x000A0000 + (minor << 8);
+                       }
+               }
+       }
+       
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -3560,6 +3837,7 @@ void Options::checkIllegalOptionCombinations()
                        if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
                                info.options.fReExport = true;
                                found = true;
+                fLinkSnapshot.recordSubUmbrella(info.path);
                                break;
                        }
                }
@@ -3582,6 +3860,7 @@ void Options::checkIllegalOptionCombinations()
                        if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) {
                                info.options.fReExport = true;
                                found = true;
+                fLinkSnapshot.recordSubLibrary(info.path);
                                break;
                        }
                }
@@ -3891,10 +4170,10 @@ void Options::checkIllegalOptionCombinations()
                }
        }
        
-       // check -pie is only used when building a dynamic main executable for 10.5
        if ( fPositionIndependentExecutable ) {
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
+                               // check -pie is only used when building a dynamic main executable for 10.5
                                if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) {
                                        if ( fIOSVersionMin == ld::iOSVersionUnset )
                                                throw "-pie can only be used when targeting Mac OS X 10.5 or later";
@@ -3902,14 +4181,15 @@ void Options::checkIllegalOptionCombinations()
                                                throw "-pie can only be used when targeting iOS 4.2 or later";
                                }
                                break;
+                       case Options::kStaticExecutable:
                        case Options::kPreload:
+                               // -pie is ok with -static or -preload
                                break;
                        case Options::kDynamicLibrary:
                        case Options::kDynamicBundle:
                                warning("-pie being ignored. It is only used when linking a main executable");
                                fPositionIndependentExecutable = false;
                                break;
-                       case Options::kStaticExecutable:
                        case Options::kObjectFile:
                        case Options::kDyld:
                        case Options::kKextBundle:
@@ -3966,6 +4246,9 @@ void Options::checkForClassic(int argc, const char* argv[])
        bool newLinker = false;
        
        // build command line buffer in case ld crashes
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+       CRSetCrashLogMessage(crashreporterBuffer);
+#endif
        const char* srcRoot = getenv("SRCROOT");
        if ( srcRoot != NULL ) {
                strlcpy(crashreporterBuffer, "SRCROOT=", crashreporterBufferSize);
@@ -4018,31 +4301,6 @@ void Options::checkForClassic(int argc, const char* argv[])
                        }
                }
        }
-
-       // -dtrace only supported by new linker
-       if( dtraceFound )
-               return;
-
-       if( archFound ) {
-               switch ( fArchitecture ) {
-               case CPU_TYPE_I386:
-                       if ( (staticFound || kextFound) && !newLinker ) {
-                               // this environment variable will disable use of ld_classic for -static links
-                               if ( getenv("LD_NO_CLASSIC_LINKER_STATIC") == NULL ) {
-                                       this->gotoClassicLinker(argc, argv);
-                               }
-                       }
-                       break;
-               }
-       }
-       else {
-               // work around for VSPTool
-               if ( staticFound ) {
-                       warning("using ld_classic");
-                       this->gotoClassicLinker(argc, argv);
-               }
-       }
-
 }
 
 void Options::gotoClassicLinker(int argc, const char* argv[])
@@ -4096,3 +4354,32 @@ void Options::gotoClassicLinker(int argc, const char* argv[])
        fprintf(stderr, "can't exec ld_classic\n");
        exit(1);
 }
+
+
+// Note, returned string buffer is own by this function.
+// It should not be freed
+// It will be reused, so clients need to strdup() if they want
+// to use it long term.
+const char* Options::demangleSymbol(const char* sym) const
+{
+       // only try to demangle symbols if -demangle on command line
+       if ( !fDemangle )
+               return sym;
+
+       // only try to demangle symbols that look like C++ symbols
+       if ( strncmp(sym, "__Z", 3) != 0 )
+               return sym;
+
+       static size_t size = 1024;
+       static char* buff = (char*)malloc(size);
+       int status;
+       
+       char* result = abi::__cxa_demangle(&sym[1], buff, &size, &status); 
+       if ( result != NULL ) {
+               // if demangling successful, keep buffer for next demangle
+               buff = result;
+               return buff;
+       }
+       return sym;
+}
+
index 5a8a7e0fa43ef3ecc52829246b3dc233c4fb08fb..be6dc56c6f17aeadf946d198362023cec60d8a26 100644 (file)
 #include <ext/hash_map>
 
 #include "ld.hpp"
+#include "Snapshot.h"
 
 extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
 extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
 
+class Snapshot;
+
 class LibraryOptions
 {
 public:
@@ -82,12 +85,42 @@ public:
        enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
        enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
 
-       struct FileInfo {
+       class FileInfo {
+    public:
                const char*                             path;
                uint64_t                                fileLen;
                time_t                                  modTime;
                LibraryOptions                  options;
-       };
+               ld::File::Ordinal               ordinal;
+               bool                                    fromFileList;
+
+               // These are used by the threaded input file parsing engine.
+               mutable int                             inputFileSlot;  // The input file "slot" assigned to this particular file
+               bool                                    readyToParse;
+
+        // The use pattern for FileInfo is to create one on the stack in a leaf function and return
+        // it to the calling frame by copy. Therefore the copy constructor steals the path string from
+        // the source, which dies with the stack frame.
+        FileInfo(FileInfo const &other) : path(other.path), fileLen(other.fileLen), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
+
+        // Create an empty FileInfo. The path can be set implicitly by checkFileExists().
+        FileInfo() : path(NULL), fileLen(0), modTime(0), options(), fromFileList(false) {};
+        
+        // Create a FileInfo for a specific path, but does not stat the file.
+        FileInfo(const char *_path) : path(strdup(_path)), fileLen(0), modTime(0), options(), fromFileList(false) {};
+
+        ~FileInfo() { if (path) ::free((void*)path); }
+        
+        // Stat the file and update fileLen and modTime.
+        // If the object already has a path the p must be NULL.
+        // If the object does not have a path then p can be any candidate path, and if the file exists the object permanently remembers the path.
+        // Returns true if the file exists, false if not.
+        bool checkFileExists(const char *p=NULL);
+        
+        // Returns true if a previous call to checkFileExists() succeeded.
+        // Returns false if the file does not exist of checkFileExists() has never been called.
+        bool missing() const { return modTime==0; }
+};
 
        struct ExtraSection {
                const char*                             segmentName;
@@ -244,6 +277,7 @@ public:
        bool                                            keepLocalSymbol(const char* symbolName) const;
        bool                                            allowTextRelocs() const { return fAllowTextRelocs; }
        bool                                            warnAboutTextRelocs() const { return fWarnTextRelocs; }
+       bool                                            kextsUseStubs() const { return fKextsUseStubs; }
        bool                                            usingLazyDylibLinking() const { return fUsingLazyDylibLinking; }
        bool                                            verbose() const { return fVerbose; }
        bool                                            makeEncryptable() const { return fEncryptable; }
@@ -282,11 +316,12 @@ public:
        bool                                            objcGc() const { return fObjCGc; }
        bool                                            objcGcOnly() const { return fObjCGcOnly; }
        bool                                            canUseThreadLocalVariables() const { return fTLVSupport; }
-       bool                                            demangleSymbols() const { return fDemangle; }
        bool                                            addVersionLoadCommand() const { return fVersionLoadCommand; }
        bool                                            addFunctionStarts() const { return fFunctionStartsLoadCommand; }
+       bool                                            addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
+       const char*                                     overridePathlibLTO() const { return fOverridePathlibLTO; }
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
        bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
        bool                                            hasWeakBitTweaks() const;
@@ -294,8 +329,18 @@ public:
        bool                                            forceNotWeak(const char* symbolName) const;
        bool                                            forceWeakNonWildCard(const char* symbolName) const;
        bool                                            forceNotWeakNonWildcard(const char* symbolName) const;
+    Snapshot&                   snapshot() const { return fLinkSnapshot; }
        bool                                            errorBecauseOfWarnings() const;
-
+       bool                                            needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
+       bool                                            needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
+       bool                                            needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
+       bool                                            needsDependentDRInfo() const { return fDependentDRInfo; }
+       uint64_t                                        sourceVersion() const { return fSourceVersion; }
+       uint32_t                                        sdkVersion() const { return fSDKVersion; }
+       const char*                                     demangleSymbol(const char* sym) const;
+    bool                                               pipelineEnabled() const { return fPipelineFifo != NULL; }
+    const char*                                        pipelineFifo() const { return fPipelineFifo; }
+       
 private:
        class CStringEquals
        {
@@ -343,7 +388,7 @@ private:
        void                                            parseOrderFile(const char* path, bool cstring);
        void                                            addSection(const char* segment, const char* section, const char* path);
        void                                            addSubLibrary(const char* name);
-       void                                            loadFileList(const char* fileOfPaths);
+       void                                            loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal);
        uint64_t                                        parseAddress(const char* addr);
        void                                            loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set);
        void                                            parseAliasFile(const char* fileOfAliases);
@@ -423,9 +468,12 @@ private:
        const char*                                                     fMapPath;
        const char*                                                     fDyldInstallPath;
        const char*                                                     fTempLtoObjectPath;
+       const char*                                                     fOverridePathlibLTO;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
+       uint64_t                                                        fSourceVersion;
+       uint32_t                                                        fSDKVersion;
        bool                                                            fExecutableStack;
        bool                                                            fNonExecutableHeap;
        bool                                                            fDisableNonExecutableHeap;
@@ -454,6 +502,7 @@ private:
        bool                                                            fDeadStripDylibs;
        bool                                                            fAllowTextRelocs;
        bool                                                            fWarnTextRelocs;
+       bool                                                            fKextsUseStubs;
        bool                                                            fUsingLazyDylibLinking;
        bool                                                            fEncryptable;
        bool                                                            fOrderData;
@@ -502,9 +551,20 @@ private:
        bool                                                            fFunctionStartsLoadCommand;
        bool                                                            fFunctionStartsForcedOn;
        bool                                                            fFunctionStartsForcedOff;
+       bool                                                            fDataInCodeInfoLoadCommand;
        bool                                                            fCanReExportSymbols;
        bool                                                            fObjcCategoryMerging;
        bool                                                            fPageAlignDataAtoms;
+       bool                                                            fNeedsThreadLoadCommand;
+       bool                                                            fEntryPointLoadCommand;
+       bool                                                            fEntryPointLoadCommandForceOn;
+       bool                                                            fEntryPointLoadCommandForceOff;
+       bool                                                            fSourceVersionLoadCommand;
+       bool                                                            fSourceVersionLoadCommandForceOn;
+       bool                                                            fSourceVersionLoadCommandForceOff;      
+       bool                                                            fDependentDRInfo;
+       bool                                                            fDependentDRInfoForcedOn;
+       bool                                                            fDependentDRInfoForcedOff;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
@@ -526,6 +586,9 @@ private:
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
        bool                                                            fSaveTempFiles;
+    mutable Snapshot                  fLinkSnapshot;
+    bool                              fSnapshotRequested;
+    const char *                      fPipelineFifo;
 };
 
 
index f217eb0675d13d391d8c47b215a5bb4e645a82fa..6fc91e8ca076ba39975b91f0ba7239848995e98d 100644 (file)
@@ -72,11 +72,12 @@ namespace tool {
 OutputFile::OutputFile(const Options& opts) 
        :
                hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
-               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), 
+               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), hasDataInCode(false), 
                headerAndLoadCommandsSection(NULL),
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
+               dataInCodeSection(NULL), dependentDRsSection(NULL), 
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
@@ -87,6 +88,8 @@ OutputFile::OutputFile(const Options& opts)
                _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
+               _hasDataInCodeInfo(opts.addDataInCodeInfo()),
+               _hasDependentDRInfo(opts.needsDependentDRInfo()),
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
@@ -109,7 +112,9 @@ OutputFile::OutputFile(const Options& opts)
                _weakBindingInfoAtom(NULL),
                _exportInfoAtom(NULL),
                _splitSegInfoAtom(NULL),
-               _functionStartsAtom(NULL)
+               _functionStartsAtom(NULL),
+               _dataInCodeAtom(NULL),
+               _dependentDRInfoAtom(NULL)
 {
 }
 
@@ -179,10 +184,14 @@ bool OutputFile::findSegment(ld::Internal& state, uint64_t addr, uint64_t* start
 
 void OutputFile::assignAtomAddresses(ld::Internal& state)
 {
+       const bool log = false;
+       if ( log ) fprintf(stderr, "assignAtomAddresses()\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               if ( log ) fprintf(stderr, "  section=%s/%s\n", sect->segmentName(), sect->sectionName());
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
+                       if ( log ) fprintf(stderr, "    atom=%p, name=%s\n", atom, atom->name());
                        switch ( sect-> type() ) {
                                case ld::Section::typeImportProxies:
                                        // want finalAddress() of all proxy atoms to be zero
@@ -239,6 +248,18 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _functionStartsAtom->encode();
        }
 
+       if ( _options.addDataInCodeInfo() ) {
+               // build data-in-code info  
+               assert(_dataInCodeAtom != NULL);
+               _dataInCodeAtom->encode();
+       }
+       
+       if ( _options.needsDependentDRInfo() ) {
+               // build dependent dylib DR info  
+               assert(_dependentDRInfoAtom != NULL);
+               _dependentDRInfoAtom->encode();
+       }
+
        // build classic symbol table  
        assert(_symbolTableAtom != NULL);
        _symbolTableAtom->encode();
@@ -572,8 +593,8 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                        }
                }
                
-               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
-                                                       sect->address, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
+               if ( log ) fprintf(stderr, "  address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
+                                                       sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
                                                        sect->segmentName(), sect->sectionName());
                // update running totals
                if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
@@ -605,6 +626,9 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                if ( hasZeroForFileOffset(sect) ) {
                        // fileoff of zerofill sections is moot, but historically it is set to zero
                        sect->fileOffset = 0;
+
+                       // <rdar://problem/10445047> align file offset with address layout
+                       fileOffset += sect->alignmentPaddingBytes;
                }
                else {
                        // page align file offset at start of each segment
@@ -713,6 +737,11 @@ uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup
                        return (*target)->finalAddress();
                case ld::Fixup::bindingsIndirectlyBound:
                        *target = state.indirectBindingTable[fixup->u.bindingIndex];
+               #ifndef NDEBUG
+                       if ( ! (*target)->finalAddressMode() ) {
+                               throwf("reference to symbol (which has not been assigned an address) %s", (*target)->name());
+                       }
+               #endif
                        return (*target)->finalAddress();
        }
        throw "unexpected binding";
@@ -1205,6 +1234,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                assert(fit->binding == ld::Fixup::bindingDirectlyBound);
                                accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
                                break;
+                       case ld::Fixup::kindDataInCodeStartData:
+                       case ld::Fixup::kindDataInCodeStartJT8:
+                       case ld::Fixup::kindDataInCodeStartJT16:
+                       case ld::Fixup::kindDataInCodeStartJT32:
+                       case ld::Fixup::kindDataInCodeStartJTA32:
+                       case ld::Fixup::kindDataInCodeEnd:
+                               break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
@@ -1529,35 +1565,8 @@ bool OutputFile::hasZeroForFileOffset(const ld::Section* sect)
        return false;
 }
 
-
-void OutputFile::writeOutputFile(ld::Internal& state)
+void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
 {
-       // for UNIX conformance, error if file exists and is not writable
-       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
-               throwf("can't write output file: %s", _options.outputFilePath());
-
-       int permissions = 0777;
-       if ( _options.outputKind() == Options::kObjectFile )
-               permissions = 0666;
-       // Calling unlink first assures the file is gone so that open creates it with correct permissions
-       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
-       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
-       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
-       struct stat stat_buf;
-       if ( (stat(_options.outputFilePath(), &stat_buf) != -1) && (stat_buf.st_mode & S_IFREG) )
-               (void)unlink(_options.outputFilePath());
-
-       // try to allocate buffer for entire output file content
-       uint8_t* wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
-       if ( wholeBuffer == NULL )
-               throwf("can't create buffer of %llu bytes for output", _fileSize);
-       
-       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
-               uint8_t bits[16];
-               ::uuid_generate_random(bits);
-               _headersAndLoadCommandAtom->setUUID(bits);
-       }
-
        // have each atom write itself
        uint64_t fileOffsetOfEndOfLastAtom = 0;
        uint64_t mhAddress = 0;
@@ -1598,74 +1607,153 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                        }
                }
        }
+}
+
+
+void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
+{
+       const bool log = false;
+       if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
+               uint8_t digest[CC_MD5_DIGEST_LENGTH];
+               uint32_t        stabsStringsOffsetStart;
+               uint32_t        tabsStringsOffsetEnd;
+               uint32_t        stabsOffsetStart;
+               uint32_t        stabsOffsetEnd;
+               if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
+                       // find two areas of file that are stabs info and should not contribute to checksum
+                       uint64_t stringPoolFileOffset = 0;
+                       uint64_t symbolTableFileOffset = 0;
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->type() == ld::Section::typeLinkEdit ) {
+                                       if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
+                                               stringPoolFileOffset = sect->fileOffset;
+                                       else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
+                                               symbolTableFileOffset = sect->fileOffset;
+                               }
+                       }
+                       uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
+                       uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
+                       uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
+                       uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
+                       if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+                       assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+                       
+                       CC_MD5_CTX md5state;
+                       CC_MD5_Init(&md5state);
+                       // checksum everything up to first stabs nlist
+                       if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
+                       CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
+                       // checkusm everything after last stabs nlist and up to first stabs string
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
+                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
+                       // checksum everything after last stabs string to end of file
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
+                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+                       CC_MD5_Final(digest, &md5state);
+                       if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
+                                                          digest[3], digest[4], digest[5], digest[6],  digest[7]);
+               }
+               else {
+                       CC_MD5(wholeBuffer, _fileSize, digest);
+               }
+               // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+               digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+               digest[8] = ( digest[8] & 0x3F ) | 0x80;
+               // update buffer with new UUID
+               _headersAndLoadCommandAtom->setUUID(digest);
+               _headersAndLoadCommandAtom->recopyUUIDCommand();
+       }
+}
        
-       // compute UUID 
-       if ( _options.UUIDMode() == Options::kUUIDContent ) {
-               const bool log = false;
-               if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
-                       uint8_t digest[CC_MD5_DIGEST_LENGTH];
-                       uint32_t        stabsStringsOffsetStart;
-                       uint32_t        tabsStringsOffsetEnd;
-                       uint32_t        stabsOffsetStart;
-                       uint32_t        stabsOffsetEnd;
-                       if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
-                               // find two areas of file that are stabs info and should not contribute to checksum
-                               uint64_t stringPoolFileOffset = 0;
-                               uint64_t symbolTableFileOffset = 0;
-                               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-                                       ld::Internal::FinalSection* sect = *sit;
-                                       if ( sect->type() == ld::Section::typeLinkEdit ) {
-                                               if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
-                                                       stringPoolFileOffset = sect->fileOffset;
-                                               else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
-                                                       symbolTableFileOffset = sect->fileOffset;
-                                       }
-                               }
-                               uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
-                               uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
-                               uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
-                               uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
-                               if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
-                               assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
-                               
-                               CC_MD5_CTX md5state;
-                               CC_MD5_Init(&md5state);
-                               // checksum everything up to first stabs nlist
-                               if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
-                               // checkusm everything after last stabs nlist and up to first stabs string
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
-                               // checksum everything after last stabs string to end of file
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
-                               CC_MD5_Final(digest, &md5state);
-                               if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
-                                                                                                                                       digest[3], digest[4], digest[5], digest[6],  digest[7]);
-                       }
-                       else {
-                               CC_MD5(wholeBuffer, _fileSize, digest);
-                       }
-                       // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
-                       digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
-                       digest[8] = ( digest[8] & 0x3F ) | 0x80;
-                       // update buffer with new UUID
-                       _headersAndLoadCommandAtom->setUUID(digest);
-                       _headersAndLoadCommandAtom->recopyUUIDCommand();
+       
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+       // for UNIX conformance, error if file exists and is not writable
+       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+               throwf("can't write output file: %s", _options.outputFilePath());
+
+       mode_t permissions = 0777;
+       if ( _options.outputKind() == Options::kObjectFile )
+               permissions = 0666;
+       mode_t umask = ::umask(0);
+       ::umask(umask); // put back the original umask
+       permissions &= ~umask;
+       // Calling unlink first assures the file is gone so that open creates it with correct permissions
+       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
+       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+       struct stat stat_buf;
+       bool outputIsRegularFile = true;
+       if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+               if (stat_buf.st_mode & S_IFREG) {
+                       (void)unlink(_options.outputFilePath());
+               } else {
+                       outputIsRegularFile = false;
+               }
+       }
+
+       int fd;
+       // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+       const char filenameTemplate[] = ".ld_XXXXXX";
+       char tmpOutput[PATH_MAX];
+       uint8_t *wholeBuffer;
+       if (outputIsRegularFile) {
+               strcpy(tmpOutput, _options.outputFilePath());
+               // If the path is too long to add a suffix for a temporary name then
+               // just fall back to using the output path. 
+               if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+                       strcat(tmpOutput, filenameTemplate);
+                       fd = mkstemp(tmpOutput);
+               } else {
+                       fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
                }
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
+               ftruncate(fd, _fileSize);
+               
+               wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+               if ( wholeBuffer == MAP_FAILED )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       } else {
+               fd = open(_options.outputFilePath(), O_WRONLY);
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
+               // try to allocate buffer for entire output file content
+               wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
+               if ( wholeBuffer == NULL )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       }
+       
+       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
+               uint8_t bits[16];
+               ::uuid_generate_random(bits);
+               _headersAndLoadCommandAtom->setUUID(bits);
        }
 
-       // write whole output file in one chunk
-       int fd = open(_options.outputFilePath(), O_CREAT | O_WRONLY | O_TRUNC, permissions);
-       if ( fd == -1 ) 
-               throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
-       if ( ::pwrite(fd, wholeBuffer, _fileSize, 0) == -1 )
-               throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
-       close(fd);
-       free(wholeBuffer);
+       writeAtoms(state, wholeBuffer);
+       
+       // compute UUID 
+       if ( _options.UUIDMode() == Options::kUUIDContent )
+               computeContentUUID(state, wholeBuffer);
+
+       if (outputIsRegularFile) {
+               if ( ::chmod(tmpOutput, permissions) == -1 ) {
+                       unlink(tmpOutput);
+                       throwf("can't set permissions on output file: %s, errno=%d", tmpOutput, errno);
+               }
+               if ( ::rename(tmpOutput, _options.outputFilePath()) == -1 && strcmp(tmpOutput, _options.outputFilePath()) != 0) {
+                       unlink(tmpOutput);
+                       throwf("can't move output file in place, errno=%d", errno);
+               }
+       } else {
+               if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
+                       throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
+               }
+       }
 }
 
 struct AtomByNameSorter
@@ -1778,27 +1866,6 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                continue;
                        }
                        
-                       // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols                 
-                       if ( _options.hasWeakBitTweaks() && (atom->definition() == ld::Atom::definitionRegular) ) {
-                               const char* name = atom->name();
-                               if ( atom->scope() == ld::Atom::scopeGlobal ) {
-                                       if ( atom->combine() == ld::Atom::combineNever ) {
-                                               if ( _options.forceWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
-                                       }
-                                       else if ( atom->combine() == ld::Atom::combineByName ) {
-                                               if ( _options.forceNotWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
-                                       }
-                               }
-                               else {
-                                       if ( _options.forceWeakNonWildCard(name) )
-                                               warning("cannot force to be weak, non-external symbol %s", name);
-                                       else if ( _options.forceNotWeakNonWildcard(name) )
-                                               warning("cannot force to be not-weak, non-external symbol %s", name);
-                               }
-                       }
-                       
                        switch ( atom->scope() ) {
                                case ld::Atom::scopeTranslationUnit:
                                        if ( _options.keepLocalSymbol(atom->name()) ) { 
@@ -1879,6 +1946,7 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
 void OutputFile::addPreloadLinkEdit(ld::Internal& state)
 {
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
@@ -1897,6 +1965,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
@@ -1915,6 +1985,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
@@ -1933,6 +2005,7 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
                default:
                        throw "architecture not supported for -preload";
        }
@@ -1947,6 +2020,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                return addPreloadLinkEdit(state);
        
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<x86>(_options, state, *this);
@@ -1980,6 +2054,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -1995,6 +2077,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
@@ -2028,6 +2112,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2043,6 +2135,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
@@ -2076,6 +2170,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2091,6 +2193,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2099,18 +2202,24 @@ void OutputFile::addLinkEdit(ld::Internal& state)
 void OutputFile::addLoadCommands(ld::Internal& state)
 {
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2485,7 +2594,15 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                                }
                                                assert(minusTarget != NULL);
                                                break;
-                     default:
+                                       case ld::Fixup::kindDataInCodeStartData:
+                                       case ld::Fixup::kindDataInCodeStartJT8:
+                                       case ld::Fixup::kindDataInCodeStartJT16:
+                                       case ld::Fixup::kindDataInCodeStartJT32:
+                                       case ld::Fixup::kindDataInCodeStartJTA32:
+                                       case ld::Fixup::kindDataInCodeEnd:
+                                               hasDataInCode = true;
+                                               break;
+                                       default:
                         break;    
                                }
                                if ( this->isStore(fit->kind) ) {
@@ -2530,7 +2647,8 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                if ( _options.warnAboutTextRelocs() )
                        warning("text reloc in %s to %s", atom->name(), target->name());
        } 
-       else if ( _options.positionIndependentExecutable() && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+       else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
+               && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
                        warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
@@ -2568,9 +2686,10 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                        return;
                                }
                                // Have direct reference to weak-global.  This should be an indrect reference
+                               const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
                                warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
                                                "This was likely caused by different translation units being compiled with different visibility settings.",
-                                                atom->name(), target->name());
+                                                 demangledName, _options.demangleSymbol(target->name()));
                        }
                        return;
                }
@@ -2596,9 +2715,10 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                return;
                        }
                        // Have direct reference to weak-global.  This should be an indrect reference
+                       const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
                        warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
                                        "This was likely caused by different translation units being compiled with different visibility settings.",
-                                        atom->name(), target->name());
+                                        demangledName, _options.demangleSymbol(target->name()));
                }
                return;
        }
@@ -2620,7 +2740,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        uint8_t rebaseType = REBASE_TYPE_POINTER;
        uint8_t type = BIND_TYPE_POINTER;
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-       bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->forcedWeakLinked()));
+    bool weak_import = (fixupWithTarget->weakImport || ((dylib != NULL) && dylib->forcedWeakLinked()));
        uint64_t address =  atom->finalAddress() + fixupWithTarget->offsetInAtom;
        uint64_t addend = targetAddend - minusTargetAddend;
 
@@ -2716,6 +2836,22 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
                        rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
                }
+               if ( (addend != 0) && _options.sharedRegionEligible() ) {
+                       // make sure the addend does not cause the pointer to point outside the target's segment
+                       // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+                       uint64_t targetAddress = target->finalAddress();
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sct = *sit;
+                               uint64_t sctEnd = (sct->address+sct->size);
+                               if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+                                       if ( (targetAddress+addend) > sctEnd ) {
+                                               warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
+                                                               "That large of an addend may disable %s from being put in the dyld shared cache.", 
+                                                               atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+                                       }
+                               }
+                       }
+               }
                _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
        }
        if ( needsBinding ) {
@@ -2745,10 +2881,20 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                return;
        
        // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
-       if ( (sect->type() == ld::Section::typeNonLazyPointer) && (_options.outputKind() != Options::kKextBundle) ) {
-               assert(target != NULL);
-               assert(fixupWithTarget != NULL);
-               return;
+       if ( sect->type() == ld::Section::typeNonLazyPointer ) {
+               // except kexts and static pie which *do* use relocations
+               switch (_options.outputKind()) {
+                       case Options::kKextBundle:
+                               break;
+                       case Options::kStaticExecutable:
+                               if ( _options.positionIndependentExecutable() )
+                                       break;
+                               // else fall into default case
+                       default:
+                               assert(target != NULL);
+                               assert(fixupWithTarget != NULL);
+                               return;
+               }
        }
        
        // no need to rebase or bind PCRel stores
@@ -3091,8 +3237,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                        //              uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
                        //}
                        // write table of object files
-                       std::map<const ld::File*, uint32_t> readerToOrdinal;
-                       std::map<uint32_t, const ld::File*> ordinalToReader;
+                       std::map<const ld::File*, ld::File::Ordinal> readerToOrdinal;
+                       std::map<ld::File::Ordinal, const ld::File*> ordinalToReader;
                        std::map<const ld::File*, uint32_t> readerToFileOrdinal;
                        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                                ld::Internal::FinalSection* sect = *sit;
@@ -3103,8 +3249,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                                        const ld::File* reader = atom->file();
                                        if ( reader == NULL )
                                                continue;
-                                       uint32_t readerOrdinal = reader->ordinal();
-                                       std::map<const ld::File*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
+                                       ld::File::Ordinal readerOrdinal = reader->ordinal();
+                                       std::map<const ld::File*, ld::File::Ordinal>::iterator pos = readerToOrdinal.find(reader);
                                        if ( pos == readerToOrdinal.end() ) {
                                                readerToOrdinal[reader] = readerOrdinal;
                                                ordinalToReader[readerOrdinal] = reader;
@@ -3113,13 +3259,10 @@ void OutputFile::writeMapFile(ld::Internal& state)
                        }
                        fprintf(mapFile, "# Object files:\n");
                        fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
-                       uint32_t fileIndex = 0;
-                       readerToFileOrdinal[NULL] = fileIndex++;
-                       for(std::map<uint32_t, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
-                               if ( it->first != 0 ) {
-                                       fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
-                                       readerToFileOrdinal[it->second] = fileIndex++;
-                               }
+                       uint32_t fileIndex = 1;
+                       for(std::map<ld::File::Ordinal, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
+                               fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
+                               readerToFileOrdinal[it->second] = fileIndex++;
                        }
                        // write table of sections
                        fprintf(mapFile, "# Sections:\n");
@@ -3196,8 +3339,8 @@ public:
        bool operator()(const ld::Atom* left, const ld::Atom* right) const
        {
                // first sort by reader
-               uint32_t leftFileOrdinal  = left->file()->ordinal();
-               uint32_t rightFileOrdinal = right->file()->ordinal();
+               ld::File::Ordinal leftFileOrdinal  = left->file()->ordinal();
+               ld::File::Ordinal rightFileOrdinal = right->file()->ordinal();
                if ( leftFileOrdinal!= rightFileOrdinal)
                        return (leftFileOrdinal < rightFileOrdinal);
 
@@ -3300,11 +3443,13 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                const char* newDirPath;
                const char* newFilename;
                //fprintf(stderr, "debug note for %s\n", atom->name());
-               if ( atom->translationUnitSource(&newDirPath, &newFilename) ) {
+               // guard against dwarf info that has no directory <rdar://problem/10991352>
+               if ( atom->translationUnitSource(&newDirPath, &newFilename) && (newDirPath != NULL)) {
                        // need SO's whenever the translation unit source file changes
                        if ( newFilename != filename ) {
                                // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
-                               if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
+                               size_t len = strlen(newDirPath);
+                               if ( (newDirPath != NULL) && (len > 1 ) && (newDirPath[len-1] != '/') )
                                        asprintf((char**)&newDirPath, "%s/", newDirPath);
                                if ( filename != NULL ) {
                                        // translation unit change, emit ending SO
index 84017169c39dd6a865a5abc58e7c6b1cb06d9a00..d3567ae51764888aaad53180371dd401e67b883a 100644 (file)
@@ -74,6 +74,7 @@ public:
        bool                                            _noReExportedDylibs;
        bool                                            hasThreadLocalVariableDefinitions;
        bool                                            pieDisabled;
+       bool                                            hasDataInCode;
        ld::Internal::FinalSection*     headerAndLoadCommandsSection;
        ld::Internal::FinalSection*     rebaseSection;
        ld::Internal::FinalSection*     bindingSection;
@@ -82,6 +83,8 @@ public:
        ld::Internal::FinalSection*     exportSection;
        ld::Internal::FinalSection*     splitSegInfoSection;
        ld::Internal::FinalSection*     functionStartsSection;
+       ld::Internal::FinalSection*     dataInCodeSection;
+       ld::Internal::FinalSection*     dependentDRsSection;
        ld::Internal::FinalSection*     symbolTableSection;
        ld::Internal::FinalSection*     stringPoolSection;
        ld::Internal::FinalSection*     localRelocationsSection;
@@ -137,6 +140,8 @@ public:
        };
        
 private:
+       void                                            writeAtoms(ld::Internal& state, uint8_t* wholeBuffer);
+       void                                            computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer);
        void                                            buildDylibOrdinalMapping(ld::Internal&);
        bool                                            hasOrdinalForInstallPath(const char* path, int* ordinal);
        void                                            addLoadCommands(ld::Internal& state);
@@ -243,6 +248,8 @@ private:
        const bool                                                              _hasSectionRelocations;
        const bool                                                              _hasSplitSegInfo;
        const bool                                                              _hasFunctionStartsInfo;
+       const bool                                                              _hasDataInCodeInfo;
+       const bool                                                              _hasDependentDRInfo;
                  bool                                                          _hasDynamicSymbolTable;
                  bool                                                          _hasLocalRelocations;
                  bool                                                          _hasExternalRelocations;
@@ -280,6 +287,8 @@ public:
        class LinkEditAtom*                                             _exportInfoAtom;
        class LinkEditAtom*                                             _splitSegInfoAtom;
        class LinkEditAtom*                                             _functionStartsAtom;
+       class LinkEditAtom*                                             _dataInCodeAtom;
+       class LinkEditAtom*                                             _dependentDRInfoAtom;
 };
 
 } // namespace tool 
index 2502820c01b6a5210bdbe225cf4a0249eb427cbf..3a2878886e1d6a1a959987ebf96bfe575680f0f5 100644 (file)
@@ -292,6 +292,7 @@ void Resolver::buildAtomList()
        // each input files contributes initial atoms
        _atoms.reserve(1024);
        _inputFiles.forEachInitialAtom(*this);
+    
        _completedInitialObjectFiles = true;
        
        //_symbolTable.printStatistics();
@@ -332,10 +333,6 @@ void Resolver::doFile(const ld::File& file)
                if ( objFile->debugInfo() == ld::relocatable::File::kDebugInfoDwarf )
                        _internal.someObjectFileHasDwarf = true;
                        
-               // remember if any objc classes built for fix-and-continue
-               if ( objFile->objcReplacementClasses() )
-                       _internal.hasObjcReplacementClasses = true;
-                       
                // remember if any .o file did not have MH_SUBSECTIONS_VIA_SYMBOLS bit set
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
@@ -427,16 +424,16 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                        }
                                                        else if ( _options.outputKind() == Options::kDynamicLibrary ) {
                                                                if ( atom.file() != NULL )
-                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                                                else
-                                                                       warning("target OS does not support re-exporting symbol %s\n", SymbolTable::demangle(name));
+                                                                       warning("target OS does not support re-exporting symbol %s\n", _options.demangleSymbol(name));
                                                        }
                                                }
                                                else {
                                                        if ( atom.file() != NULL )
-                                                               warning("cannot export hidden symbol %s from %s", SymbolTable::demangle(name), atom.file()->path());
+                                                               warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.file()->path());
                                                        else
-                                                               warning("cannot export hidden symbol %s", SymbolTable::demangle(name));
+                                                               warning("cannot export hidden symbol %s", _options.demangleSymbol(name));
                                                }
                                        }
                                }
@@ -446,7 +443,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
                                        }
                                        else {
-                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                        }
                                }
                                break;
@@ -457,7 +454,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                        //fprintf(stderr, "demote %s to hidden\n", name);
                                }
                                if ( _options.canReExportSymbols() && _options.shouldReExport(name) ) {
-                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                }
                                break;
                }
@@ -491,11 +488,7 @@ void Resolver::doAtom(const ld::Atom& atom)
        // remember if any atoms are proxies that require LTO
        if ( atom.contentType() == ld::Atom::typeLTOtemporary )
                _haveLLVMObjs = true;
-       
-       // if we've already partitioned into final sections, and lto needs a symbol very late, add it
-       if ( _addToFinalSection ) 
-               _internal.addAtom(atom);
-       
+               
        if ( _options.deadCodeStrip() ) {
                // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
                if ( atom.dontDeadStrip() )
@@ -856,9 +849,10 @@ void Resolver::deadStripOptimize()
        // now remove all non-live atoms from _atoms
        const bool log = false;
        if ( log ) {
-               fprintf(stderr, "deadStripOptimize() all atoms with liveness:\n");
+               fprintf(stderr, "deadStripOptimize() all %ld atoms with liveness:\n", _atoms.size());
                for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
-                       fprintf(stderr, "  live=%d  name=%s\n", (*it)->live(), (*it)->name());
+                       const ld::File* file = (*it)->file();
+                       fprintf(stderr, "  live=%d  atom=%p  name=%s from=%s\n", (*it)->live(), *it, (*it)->name(),  (file ? file->path() : "<internal>"));
                }
        }
        
@@ -869,9 +863,56 @@ void Resolver::deadStripOptimize()
        else {
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
        }
+
+       if ( log ) {
+               fprintf(stderr, "deadStripOptimize() %ld remaining atoms\n", _atoms.size());
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       fprintf(stderr, "  live=%d  atom=%p  name=%s\n", (*it)->live(), *it, (*it)->name());
+               }
+       }
 }
 
 
+// This is called when LTO is used but -dead_strip is not used.
+// Some undefines were eliminated by LTO, but others were not.
+void Resolver::remainingUndefines(std::vector<const char*>& undefs)
+{
+       StringSet  undefSet;
+       // search all atoms for references that are unbound
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                       switch ( (ld::Fixup::TargetBinding)fit->binding ) {
+                               case ld::Fixup::bindingByNameUnbound:
+                                       assert(0 && "should not be by-name this late");
+                                       undefSet.insert(fit->u.name);
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       if ( _internal.indirectBindingTable[fit->u.bindingIndex] == NULL ) {
+                                               undefSet.insert(_symbolTable.indirectName(fit->u.bindingIndex));
+                                       }
+                                       break;
+                               case ld::Fixup::bindingByContentBound:
+                               case ld::Fixup::bindingNone:
+                               case ld::Fixup::bindingDirectlyBound:
+                                       break;
+                       }
+               }
+       }
+       // look for any initial undefines that are still undefined
+       for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+               if ( ! _symbolTable.hasName(*uit) ) {
+                       undefSet.insert(*uit);
+               }
+       }
+       
+       // copy set to vector
+       for (StringSet::const_iterator it=undefSet.begin(); it != undefSet.end(); ++it) {
+        fprintf(stderr, "undef: %s\n", *it);
+               undefs.push_back(*it);
+       }
+}
+
 void Resolver::liveUndefines(std::vector<const char*>& undefs)
 {
        StringSet  undefSet;
@@ -990,7 +1031,7 @@ bool Resolver::printReferencedBy(const char* name, SymbolTable::IndirectBindingS
                                                ++foundReferenceCount;
                                        }
                                        else {
-                                               fprintf(stderr, "      %s in %s\n", SymbolTable::demangle(atom->name()), pathLeafName(atom->file()->path()));
+                                               fprintf(stderr, "      %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->file()->path()));
                                                ++foundReferenceCount;
                                                break; // if undefined used twice in a function, only show first
                                        }
@@ -1029,9 +1070,10 @@ void Resolver::checkUndefines(bool force)
                        break;
        }
        std::vector<const char*> unresolvableUndefines;
-       // <rdar://problem/10052396> LTO many have eliminated need for some undefines
-       if ( _options.deadCodeStrip() || _haveLLVMObjs ) 
+       if ( _options.deadCodeStrip() )
                this->liveUndefines(unresolvableUndefines);
+    else if( _haveLLVMObjs ) 
+               this->remainingUndefines(unresolvableUndefines); // <rdar://problem/10052396> LTO may have eliminated need for some undefines
        else    
                _symbolTable.undefines(unresolvableUndefines);
 
@@ -1056,7 +1098,7 @@ void Resolver::checkUndefines(bool force)
                        for (int i=0; i < unresolvableCount; ++i) {
                                const char* name = unresolvableUndefines[i];
                                unsigned int slot = _symbolTable.findSlotForName(name);
-                               fprintf(stderr, "  \"%s\", referenced from:\n", SymbolTable::demangle(name));
+                               fprintf(stderr, "  \"%s\", referenced from:\n", _options.demangleSymbol(name));
                                // scan all atoms for references
                                bool foundAtomReference = printReferencedBy(name, slot);
                                // scan command line options
@@ -1174,8 +1216,6 @@ const ld::Atom* Resolver::entryPoint(bool searchArchives)
                else if ( _internal.indirectBindingTable[slot]->definition() == ld::Atom::definitionProxy ) {
                        if ( makingDylib ) 
                                throwf("-init function (%s) found in linked dylib, must be in dylib being linked", symbolName);
-                       else
-                               throwf("entry point (%s) found in linked dylib, must be in executable being linked", symbolName);
                }
                return _internal.indirectBindingTable[slot];
        }
@@ -1262,7 +1302,17 @@ void Resolver::fillInInternalState()
 
 void Resolver::removeCoalescedAwayAtoms()
 {
+       const bool log = false;
+       if ( log ) {
+               fprintf(stderr, "removeCoalescedAwayAtoms() starts with %lu atoms\n", _atoms.size());
+       }
        _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), AtomCoalescedAway()), _atoms.end());
+       if ( log ) {
+               fprintf(stderr, "removeCoalescedAwayAtoms() after removing coalesced atoms, %lu remain\n", _atoms.size());
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       fprintf(stderr, "  atom=%p %s\n", *it, (*it)->name());
+               }
+       }
 }
 
 void Resolver::linkTimeOptimize()
@@ -1275,7 +1325,7 @@ void Resolver::linkTimeOptimize()
        lto::OptimizeOptions optOpt;
        optOpt.outputFilePath                           = _options.outputFilePath();
        optOpt.tmpObjectFilePath                        = _options.tempLtoObjectPath();
-       optOpt.allGlobalsAReDeadStripRoots      = _options.allGlobalsAreDeadStripRoots();
+       optOpt.preserveAllGlobals                       = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
        optOpt.verbose                                          = _options.verbose();
        optOpt.saveTemps                                        = _options.saveTempFiles();
        optOpt.pie                                                      = _options.positionIndependentExecutable();
@@ -1289,7 +1339,7 @@ void Resolver::linkTimeOptimize()
        
        std::vector<const ld::Atom*>            newAtoms;
        std::vector<const char*>                        additionalUndefines; 
-       if ( ! lto::optimize(_atoms, _internal, _inputFiles.nextInputOrdinal(), optOpt, *this, newAtoms, additionalUndefines) )
+       if ( ! lto::optimize(_atoms, _internal, optOpt, *this, newAtoms, additionalUndefines) )
                return; // if nothing done
                
        
@@ -1299,36 +1349,12 @@ void Resolver::linkTimeOptimize()
                
        // some atoms might have been optimized way (marked coalesced), remove them
        this->removeCoalescedAwayAtoms();
-       
-       // add new atoms into their final section
-       for (std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it) {
-               _internal.addAtom(**it);
-       }
 
-       // remove temp lto section and move all of its atoms to their final section
-       ld::Internal::FinalSection* tempLTOsection = NULL;
-       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
-               ld::Internal::FinalSection* sect = *sit;
-               if ( sect->type() == ld::Section::typeTempLTO ) {
-                       tempLTOsection = sect;
-                       // remove temp lto section from final image
-                       _internal.sections.erase(sit);
-                       break;
-               }
-       }
-       // lto atoms now have proper section info, so add to final section
-       if ( tempLTOsection != NULL ) {
-               for (std::vector<const ld::Atom*>::iterator ait=tempLTOsection->atoms.begin(); ait != tempLTOsection->atoms.end(); ++ait) {
-                       const ld::Atom* atom = *ait;
-                       if ( ! atom->coalescedAway() ) {
-                               this->convertReferencesToIndirect(*atom);
-                               _internal.addAtom(*atom);
-                       }
-               }
-       }
-       
+       // run through all atoms again and make sure newly codegened atoms have refernces bound
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) 
+               this->convertReferencesToIndirect(**it);
+
        // resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
-       _addToFinalSection = true;
        for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
                const char *targetName = *uit;
                // these symbols may or may not already be in linker's symbol table
@@ -1336,7 +1362,6 @@ void Resolver::linkTimeOptimize()
                        _inputFiles.searchLibraries(targetName, true, true, false, *this);
                }
        }
-       _addToFinalSection = false;
 
        // if -dead_strip on command line
        if ( _options.deadCodeStrip() ) {
@@ -1346,19 +1371,11 @@ void Resolver::linkTimeOptimize()
                }
                // and re-compute dead code
                this->deadStripOptimize();
-
-               // remove newly dead atoms from each section
-               for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
-                       ld::Internal::FinalSection* sect = *sit;
-                       sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), NotLive()), sect->atoms.end());
-               }
        }
        
        if ( _options.outputKind() == Options::kObjectFile ) {
                // if -r mode, add proxies for new undefines (e.g. ___stack_chk_fail)
-               _addToFinalSection = true;
                this->resolveUndefines();
-               _addToFinalSection = false;
        }
        else {
                // last chance to check for undefines
@@ -1370,6 +1387,39 @@ void Resolver::linkTimeOptimize()
 }
 
 
+void Resolver::tweakWeakness()
+{
+       // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols                 
+       if ( _options.hasWeakBitTweaks() ) {
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = _internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               if ( atom->definition() != ld::Atom::definitionRegular ) 
+                                       continue;
+                               const char* name = atom->name();
+                               if ( atom->scope() == ld::Atom::scopeGlobal ) {
+                                       if ( atom->combine() == ld::Atom::combineNever ) {
+                                               if ( _options.forceWeak(name) )
+                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
+                                       }
+                                       else if ( atom->combine() == ld::Atom::combineByName ) {
+                                               if ( _options.forceNotWeak(name) )
+                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
+                                       }
+                               }
+                               else {
+                                       if ( _options.forceWeakNonWildCard(name) )
+                                               warning("cannot force to be weak, non-external symbol %s", name);
+                                       else if ( _options.forceNotWeakNonWildcard(name) )
+                                               warning("cannot force to be not-weak, non-external symbol %s", name);
+                               }
+                       }
+               }
+       }
+}
+
+
 void Resolver::resolve()
 {
        this->initializeState();
@@ -1381,8 +1431,10 @@ void Resolver::resolve()
        this->checkUndefines();
        this->checkDylibSymbolCollisions();
        this->removeCoalescedAwayAtoms();
-       this->fillInInternalState();
        this->linkTimeOptimize();
+       this->fillInInternalState();
+       this->tweakWeakness();
+    _symbolTable.checkDuplicateSymbols();
 }
 
 
index 65e20065740032287ba2f7b15cc3cae317f6ba9d..c7619903052f6da1ba47eb73192d5f601f3f666f 100644 (file)
@@ -57,10 +57,10 @@ namespace tool {
 class Resolver : public ld::File::AtomHandler
 {
 public:
-                                                       Resolver(const Options& opts, const InputFiles& inputs, ld::Internal& state) 
+                                                       Resolver(const Options& opts, InputFiles& inputs, ld::Internal& state) 
                                                                : _options(opts), _inputFiles(inputs), _internal(state), 
                                                                  _symbolTable(opts, state.indirectBindingTable),
-                                                                 _haveLLVMObjs(false), _addToFinalSection(false),
+                                                                 _haveLLVMObjs(false),
                                                                  _completedInitialObjectFiles(false) {}
                                                                
 
@@ -94,8 +94,9 @@ private:
        void                                    markLive(const ld::Atom& atom, WhyLiveBackChain* previous);
        bool                                    isDtraceProbe(ld::Fixup::Kind kind);
        void                                    liveUndefines(std::vector<const char*>&);
+       void                                    remainingUndefines(std::vector<const char*>&);
        bool                                    printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
-                       
+       void                                    tweakWeakness();
 
        class CStringEquals {
        public:
@@ -118,14 +119,13 @@ private:
        };
 
        const Options&                                  _options;
-       const InputFiles&                               _inputFiles;
+       InputFiles&                                             _inputFiles;
        ld::Internal&                                   _internal;
        std::vector<const ld::Atom*>    _atoms;
        std::set<const ld::Atom*>               _deadStripRoots;
        std::vector<const ld::Atom*>    _atomsWithUnresolvedReferences;
        SymbolTable                                             _symbolTable;
        bool                                                    _haveLLVMObjs;
-       bool                                                    _addToFinalSection;
        bool                                                    _completedInitialObjectFiles;
 };
 
diff --git a/src/ld/Snapshot.cpp b/src/ld/Snapshot.cpp
new file mode 100644 (file)
index 0000000..27ce370
--- /dev/null
@@ -0,0 +1,538 @@
+//
+//  Snapshot.cpp
+//  ld64
+//
+//  Created by Josh Behnke on 8/25/11.
+//  Copyright (c) 2011 Apple Inc. All rights reserved.
+//
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <time.h>
+#include <Block.h>
+
+#include "Snapshot.h"
+#include "Options.h"
+
+#include "compile_stubs.h"
+
+//#define STORE_PID_IN_SNAPSHOT 1
+
+// Well known snapshot file/directory names. These appear in the root of the snapshot.
+// They are collected together here to make managing the namespace easier.
+static const char *frameworksString         = "frameworks";         // directory containing framework stubs (mach-o files)
+static const char *dylibsString             = "dylibs";             // directory containing dylib stubs (mach-o files)
+static const char *archiveFilesString       = "archive_files";      // directory containing .a files
+static const char *origCommandLineString    = "orig_command_line";  // text file containing the original command line
+static const char *linkCommandString        = "link_command";       // text file containing the snapshot equivalent command line
+static const char *dataFilesString          = "data_files";         // arbitrary data files referenced on the command line
+static const char *objectsString            = "objects";            // directory containing object files
+static const char *frameworkStubsString     = "framework_stubs";    // directory containing framework stub info (text files)
+static const char *dylibStubsString         = "dylib_stubs";        // directory containing dylib stub info (text files)
+static const char *assertFileString         = "assert_info";        // text file containing assertion failure logs
+static const char *compileFileString        = "compile_stubs";      // text file containing compile_stubs script
+
+Snapshot *Snapshot::globalSnapshot = NULL;
+
+Snapshot::Snapshot() : fRecordArgs(false), fRecordObjects(false), fRecordDylibSymbols(false), fRecordArchiveFiles(false), fRecordUmbrellaFiles(false), fRecordDataFiles(false), fFrameworkArgAdded(false), fSnapshotLocation(NULL), fSnapshotName(NULL), fRootDir(NULL), fFilelistFile(-1), fCopiedArchives(NULL) 
+{
+    if (globalSnapshot != NULL)
+        throw "only one snapshot supported";
+    globalSnapshot = this;
+}
+
+
+Snapshot::~Snapshot() 
+{
+    // Lots of things leak under the assumption the linker is about to exit.
+}
+
+
+void Snapshot::setSnapshotPath(const char *path) 
+{
+    if (fRootDir == NULL) {
+        fSnapshotLocation = strdup(path);
+    }
+}
+
+
+void Snapshot::setSnapshotMode(SnapshotMode mode) 
+{
+    if (fRootDir == NULL) {
+        fRecordArgs = false;
+        fRecordObjects = false;
+        fRecordDylibSymbols = false;
+        fRecordArchiveFiles = false;
+        fRecordUmbrellaFiles = false;
+        fRecordDataFiles = false;
+        
+        switch (mode) {
+            case SNAPSHOT_DISABLED:
+                break;
+            case SNAPSHOT_DEBUG:
+                fRecordArgs = fRecordObjects = fRecordDylibSymbols = fRecordArchiveFiles = fRecordUmbrellaFiles = fRecordDataFiles = true;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+void Snapshot::setSnapshotName(const char *path)
+{
+    if (fRootDir == NULL) {
+        const char *base = basename((char *)path);
+        time_t now = time(NULL);
+        struct tm t;
+        localtime_r(&now, &t);
+        char buf[PATH_MAX];
+        snprintf(buf, sizeof(buf)-1, "%s-%4.4d-%2.2d-%2.2d-%2.2d%2.2d%2.2d.ld-snapshot", base, t.tm_year+1900, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+        fSnapshotName = strdup(buf);
+    }
+}
+
+
+// Construct a path string in the snapshot.
+// subdir - an optional subdirectory name
+// file - the file name
+void Snapshot::buildPath(char *buf, const char *subdir, const char *file) 
+{
+    if (fRootDir == NULL)
+        throw "snapshot not created";
+    
+    strcpy(buf, fRootDir);
+    strcat(buf, "/");
+    if (subdir) {
+        strcat(buf, subdir);
+        // implicitly create the subdirectory
+        mkdir(buf, S_IRUSR|S_IWUSR|S_IXUSR);
+        strcat(buf, "/");
+    }
+    if (file != NULL)
+        strcat(buf, basename((char *)file));
+}
+
+
+// Construct a unique path string in the snapshot. If a path collision is detected then uniquing
+// is accomplished by appending a counter to the path until there is no preexisting file.
+// subdir - an optional subdirectory name
+// file - the file name
+void Snapshot::buildUniquePath(char *buf, const char *subdir, const char *file) 
+{
+    buildPath(buf, subdir, file);
+    struct stat st;
+    if (stat(buf, &st)==0) {
+        // make it unique
+        int counter=1;
+        char *number = strrchr(buf, 0);
+        number[0]='-';
+        number++;
+        do {
+            sprintf(number, "%d", counter++);
+        } while (stat(buf, &st) == 0);
+    }
+}
+
+
+// Copy a file to the snapshot.
+// sourcePath is the original file
+// subdir is an optional subdirectory in the snapshot
+// path is an optional out parameter containing the final uniqued path in the snapshot
+// where the file was copied
+void Snapshot::copyFileToSnapshot(const char *sourcePath, const char *subdir, char *path) 
+{
+    const int copyBufSize=(1<<14); // 16kb buffer
+    static void *copyBuf = NULL;
+    if (copyBuf == NULL)
+        copyBuf = malloc(copyBufSize);
+    
+    char *file=basename((char *)sourcePath);
+    char buf[PATH_MAX];
+    if (path == NULL) path = buf;
+    buildUniquePath(path, subdir, file);
+    int out_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+    int in_fd = open(sourcePath, O_RDONLY);
+    int len;
+    if (out_fd != -1 && in_fd != -1) {
+        do {
+            len = read(in_fd, copyBuf, copyBufSize);
+            if (len > 0) write(out_fd, copyBuf, len);
+        } while (len == copyBufSize);
+    }
+    close(in_fd);
+    close(out_fd);
+}
+
+
+// Create the snapshot root directory.
+void Snapshot::createSnapshot()
+{
+    if (fRootDir == NULL) {
+        // provide default name and location
+        if (fSnapshotLocation == NULL)
+            fSnapshotLocation = "/tmp";        
+        if (fSnapshotName == NULL) {
+            setSnapshotName("ld_snapshot");
+        }
+        
+        char buf[PATH_MAX];
+        fRootDir = (char *)fSnapshotLocation;
+        buildUniquePath(buf, NULL, fSnapshotName);
+        fRootDir = strdup(buf);
+        if (mkdir(fRootDir, S_IRUSR|S_IWUSR|S_IXUSR)!=0) {
+            warning("unable to create link snapshot directory: %s", fRootDir);
+            fRootDir = NULL;
+            setSnapshotMode(SNAPSHOT_DISABLED); // don't try to write anything if we can't create snapshot dir
+        }
+        
+        buildPath(buf, NULL, compileFileString);
+        int compileScript = open(buf, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
+        write(compileScript, compile_stubs, strlen(compile_stubs));
+        close(compileScript);
+
+        SnapshotLog::iterator it;
+        for (it = fLog.begin(); it != fLog.end(); it++) {
+            void (^logItem)(void) = *it;
+            logItem();
+            Block_release(logItem);
+        }
+        fLog.erase(fLog.begin(), fLog.end());
+        
+        if (fRecordArgs) {
+            writeCommandLine(fRawArgs, origCommandLineString, true);
+            writeCommandLine(fArgs);
+        }
+        
+#if STORE_PID_IN_SNAPSHOT
+        char path[PATH_MAX];
+        buildUniquePath(path, NULL, pidString);
+        int pidfile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+        char pid_buf[32];
+        sprintf(pid_buf, "%lu\n", (long unsigned)getpid());
+        write(pidfile, pid_buf, strlen(pid_buf));
+        write(pidfile, "\n", 1);
+        close(pidfile);    
+#endif
+        
+    }
+}
+
+
+// Write the current command line vector to filename.
+void Snapshot::writeCommandLine(StringVector &args, const char *filename, bool includeCWD) 
+{
+    if (!isLazy() && fRecordArgs) {
+        // Figure out the file name and open it.
+        if (filename == NULL)
+            filename = linkCommandString;
+        char path[PATH_MAX];
+        buildPath(path, NULL, filename);
+        int argsFile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
+        FILE *argsStream = fdopen(argsFile, "w");
+        
+        if (includeCWD)
+            fprintf(argsStream, "cd %s\n", getcwd(path, sizeof(path)));
+
+        // iterate to write args, quoting as needed
+        StringVector::iterator it;
+        for (it = args.begin(); it != args.end(); it++) {
+            const char *arg = *it;
+            bool needQuotes = false;
+            for (const char *c = arg; *c != 0 && !needQuotes; c++) {
+                if (isspace(*c))
+                    needQuotes = true;
+            }
+            if (it != args.begin()) fprintf(argsStream, " ");
+            if (needQuotes) fprintf(argsStream, "\"");
+            fprintf(argsStream, "%s", arg);
+            if (needQuotes) fprintf(argsStream, "\"");
+        }
+        fprintf(argsStream, "\n");
+        fclose(argsStream);
+    }
+}
+
+
+// Store the command line args in the snapshot.
+void Snapshot::recordRawArgs(int argc, const char *argv[])
+{
+    // first store the original command line as-is
+    for (int i=0; i<argc; i++) {
+        fRawArgs.push_back(argv[i]);
+    }
+    fArgs.insert(fArgs.begin(), argv[0]);
+    fArgs.insert(fArgs.begin()+1, "-Z"); // don't search standard paths when running in the snapshot
+}
+
+
+// Adds one or more args to the snapshot link command.
+// argIndex is the index in the original raw args vector to start adding args
+// argCount is the count of args to copy from the raw args vector
+// fileArg is the index relative to argIndex of a file arg. The file is copied into the
+// snapshot and the path is fixed up in the snapshot link command. (skipped if fileArg==-1)
+void Snapshot::addSnapshotLinkArg(int argIndex, int argCount, int fileArg)
+{
+    if (fRootDir == NULL) {
+        fLog.push_back(Block_copy(^{ this->addSnapshotLinkArg(argIndex, argCount, fileArg); }));
+    } else {
+        char buf[PATH_MAX];
+        const char *subdir = dataFilesString;
+        for (int i=0, arg=argIndex; i<argCount && argIndex+1<(int)fRawArgs.size(); i++, arg++) {
+            if (i != fileArg) {
+                fArgs.push_back(fRawArgs[arg]);
+            } else {
+                if (fRecordDataFiles) {
+                    copyFileToSnapshot(fRawArgs[arg], subdir, buf);
+                    fArgs.push_back(strdup(snapshotRelativePath(buf)));
+                } else {
+                    // if we don't copy the file then just record the original path
+                    fArgs.push_back(strdup(fRawArgs[arg]));
+                }
+            }
+        }
+    }
+}
+
+// Record the -arch string
+void Snapshot::recordArch(const char *arch)
+{
+    // must be called after recordRawArgs()
+    if (fRawArgs.size() == 0)
+        throw "raw args not set";
+
+    // only need to store the arch explicitly if it is not mentioned on the command line
+    bool archInArgs = false;
+    StringVector::iterator it;
+    for (it = fRawArgs.begin(); it != fRawArgs.end() && !archInArgs; it++) {
+        const char *arg = *it;
+        if (strcmp(arg, "-arch") == 0)
+            archInArgs = true;
+    }
+    
+    if (!archInArgs) {
+        if (fRootDir == NULL) {
+            fLog.push_back(Block_copy(^{ this->recordArch(arch); }));
+        } else {
+            char path_buf[PATH_MAX];
+            buildUniquePath(path_buf, NULL, "arch");
+            int fd=open(path_buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+            write(fd, arch, strlen(arch));
+            close(fd);
+        }
+    }
+}
+
+// Record an object file in the snapshot.
+// path - the object file's path
+// fileContent - a pointer to the object file content
+// fileLength - the buffer size of fileContent
+void Snapshot::recordObjectFile(const char *path) 
+{
+    if (fRootDir == NULL) {
+        fLog.push_back(Block_copy(^{ this->recordObjectFile(path); }));
+    } else {
+        if (fRecordObjects) {
+                       char path_buf[PATH_MAX];
+                       copyFileToSnapshot(path, objectsString, path_buf);
+            
+            // lazily open the filelist file
+            if (fFilelistFile == -1) {
+                char filelist_path[PATH_MAX];
+                buildUniquePath(filelist_path, objectsString, "filelist");
+                fFilelistFile = open(filelist_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+                fArgs.push_back("-filelist");
+                fArgs.push_back(strdup(snapshotRelativePath(filelist_path)));
+                writeCommandLine(fArgs);
+            }
+            
+            // record the snapshot path in the filelist
+            const char *relative_path = snapshotRelativePath(path_buf);
+            write(fFilelistFile, relative_path, strlen(relative_path));
+            write(fFilelistFile, "\n", 1);
+        }
+    }
+}
+
+void Snapshot::addFrameworkArg(const char *framework)
+{
+    bool found=false;
+    for (unsigned i=0; i<fArgs.size()-1; i++) {
+        if (strcmp(fArgs[i], "-framework") == 0 && strcmp(fArgs[i+1], framework) == 0)
+            found = true;
+    }
+    if (!found) {
+        if (!fFrameworkArgAdded) {
+            fFrameworkArgAdded = true;
+            fArgs.push_back("-Fframeworks");
+        }
+        fArgs.push_back("-framework");
+        fArgs.push_back(strdup(framework));
+        writeCommandLine(fArgs);
+    }
+}
+
+void Snapshot::addDylibArg(const char *dylib)
+{
+    bool found=false;
+    for (unsigned i=0; i<fArgs.size()-1; i++) {
+        if (strcmp(fArgs[i], dylib) == 0)
+            found = true;
+    }
+    if (!found) {
+        char buf[ARG_MAX];
+        sprintf(buf, "%s/%s", dylibsString, dylib);
+        fArgs.push_back(strdup(buf));
+        writeCommandLine(fArgs);
+    }
+}
+
+// Record a dylib symbol reference in the snapshot.
+// (References are not written to the snapshot until writeStubDylibs() is called.)
+void Snapshot::recordDylibSymbol(ld::dylib::File* dylibFile, const char *name)
+{
+    if (fRootDir == NULL) {
+        fLog.push_back(Block_copy(^{ this->recordDylibSymbol(dylibFile, name); }));
+    } else {
+        if (fRecordDylibSymbols) {
+            // find the dylib in the table
+            DylibMap::iterator it;
+            const char *dylibPath = dylibFile->path();
+            it = fDylibSymbols.find(dylibPath);
+            bool isFramework = (strstr(dylibPath, "framework") != NULL);
+            int dylibFd;
+            if (it == fDylibSymbols.end()) {
+                // Didn't find a file descriptor for this dylib. Create one and add it to the dylib map.
+                char path_buf[PATH_MAX];
+                buildUniquePath(path_buf, isFramework ? frameworkStubsString : dylibStubsString, dylibPath);
+                dylibFd = open(path_buf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+                fDylibSymbols.insert(std::pair<const char *, int>(dylibPath, dylibFd));
+                char *base_name = strdup(basename(path_buf));
+                if (isFramework) {
+                    addFrameworkArg(base_name);
+                } else {
+                    addDylibArg(base_name);
+                }
+                writeCommandLine(fArgs);
+            } else {
+                dylibFd = it->second;
+            }
+            // Record the symbol.
+            
+            bool isIdentifier = (name[0] == '_');
+            for (const char *c = name; *c != 0 && isIdentifier; c++)
+                if (!isalnum(*c) && *c!='_')
+                    isIdentifier = false;
+            const char *prefix = "void ";
+            const char *weakAttr = "__attribute__ ((weak)) ";
+            const char *suffix = "(void){}\n";
+            if (isIdentifier) {
+                write(dylibFd, prefix, strlen(prefix));
+                if (dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name))
+                    write(dylibFd, weakAttr, strlen(weakAttr));
+                if (*name == '_') name++;
+                write(dylibFd, name, strlen(name));
+                write(dylibFd, suffix, strlen(suffix));
+            } else {
+                static int symbolCounter = 0;
+                char buf[64+strlen(name)];
+                sprintf(buf, "void s_%5.5d(void) __asm(\"%s\");\nvoid s_%5.5d(){}\n", symbolCounter, name, symbolCounter);
+                write(dylibFd, buf, strlen(buf));
+                symbolCounter++;
+            }
+        }                
+    }
+}
+
+
+// Record a .a archive in the snapshot.
+void Snapshot::recordArchive(const char *archiveFile)
+{
+    if (fRootDir == NULL) {
+        const char *copy = strdup(archiveFile);
+        fLog.push_back(Block_copy(^{ this->recordArchive(archiveFile); ::free((void *)copy); }));
+    } else {
+        if (fRecordArchiveFiles) {
+            // lazily create a vector of .a files that have been added
+            if (fCopiedArchives == NULL) {
+                fCopiedArchives = new StringVector;
+            }
+            
+            // See if we have already added this .a
+            StringVector::iterator it;
+            bool found = false;
+            for (it = fCopiedArchives->begin(); it != fCopiedArchives->end() && !found; it++) {
+                if (strcmp(archiveFile, *it) == 0)
+                    found = true;
+            }
+            
+            // If this is a new .a then copy it to the snapshot and add it to the snapshot link command.
+            if (!found) {
+                char path[PATH_MAX];
+                fCopiedArchives->push_back(archiveFile);
+                copyFileToSnapshot(archiveFile, archiveFilesString, path);
+                fArgs.push_back(strdup(snapshotRelativePath(path)));
+                writeCommandLine(fArgs);
+            }
+        }
+    }
+}
+
+void Snapshot::recordSubUmbrella(const char *frameworkPath)
+{
+    if (fRootDir == NULL) {
+        const char *copy = strdup(frameworkPath);
+        fLog.push_back(Block_copy(^{ this->recordSubUmbrella(copy); ::free((void *)copy); }));
+    } else {
+        if (fRecordUmbrellaFiles) {
+            const char *framework = basename((char *)frameworkPath);
+            char buf[PATH_MAX], wrapper[PATH_MAX];
+            strcpy(wrapper, frameworksString);
+            buildPath(buf, wrapper, NULL); // ensure the frameworks directory exists
+            strcat(wrapper, "/");
+            strcat(wrapper, framework);
+            strcat(wrapper, ".framework");
+            copyFileToSnapshot(frameworkPath, wrapper);
+            addFrameworkArg(framework);
+        }
+    }
+}
+
+void Snapshot::recordSubLibrary(const char *dylibPath)
+{
+    if (fRootDir == NULL) {
+        const char *copy = strdup(dylibPath);
+        fLog.push_back(Block_copy(^{ this->recordSubLibrary(copy); ::free((void *)copy); }));
+    } else {
+        if (fRecordUmbrellaFiles) {
+            copyFileToSnapshot(dylibPath, dylibsString);
+            addDylibArg(basename((char *)dylibPath));
+        }
+    }
+}
+
+void Snapshot::recordAssertionMessage(const char *fmt, ...)
+{
+    char *msg;
+    va_list args;
+    va_start(args, fmt);
+    vasprintf(&msg, fmt, args);
+    va_end(args);
+    if (msg != NULL) {
+        if (fRootDir == NULL) {
+            fLog.push_back(Block_copy(^{ this->recordAssertionMessage("%s", msg); free(msg); }));
+        } else {
+            char path[PATH_MAX];
+            buildPath(path, NULL, assertFileString);
+            int log = open(path, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+            write(log, msg, strlen(msg));
+            close(log);
+            free(msg);
+        }    
+    }
+}
diff --git a/src/ld/Snapshot.h b/src/ld/Snapshot.h
new file mode 100644 (file)
index 0000000..8cfd17e
--- /dev/null
@@ -0,0 +1,153 @@
+//
+//  Snapshot.h
+//  ld64
+//
+//  Created by Josh Behnke on 8/25/11.
+//  Copyright (c) 2011 Apple Inc. All rights reserved.
+//
+
+#ifndef ld64_Snapshot_h
+#define ld64_Snapshot_h
+#include <stdint.h>
+#include <string.h>
+#include <map>
+#include <vector>
+
+#include "ld.hpp"
+
+class Options;
+class SnapshotLogItem;
+
+class Snapshot {
+    
+public:
+    static Snapshot *globalSnapshot;
+    
+    typedef enum { 
+        SNAPSHOT_DISABLED, // nothing is recorded
+        SNAPSHOT_DEBUG, // records: .o, .dylib, .framework, .a, and other data files
+    } SnapshotMode;
+    
+    Snapshot();
+    ~Snapshot();
+    
+    // Control the data captured in the snapshot
+    void setSnapshotMode(SnapshotMode mode);
+    
+    // Use the basename of path to construct the snapshot name.
+    // Must be called prior to createSnapshot().
+    void setSnapshotName(const char *path);
+    
+    // Set the directory in which the snapshot will be created.
+    // Must be called prior to createSnapshot().
+    void setSnapshotPath(const char *path);
+
+    // Stores the linker command line in the snapshot
+    void recordRawArgs(int argc, const char *argv[]);
+    
+    // Adds one or more args to the snapshot link command.
+    // argIndex is the index in the original raw args vector to start adding args
+    // argCount is the count of args to copy from the raw args vector
+    // fileArg is the index relative to argIndex of a file arg. The file is copied into the
+    // snapshot and the path is fixed up in the snapshot link command. (skipped if fileArg==-1)
+    // recordRawArgs() must be called prior to the first call to addSnapshotLinkArg()
+    void addSnapshotLinkArg(int argIndex, int argCount=1, int fileArg=-1);
+    
+    // record the -arch string
+    void recordArch(const char *arch);
+    
+    // Stores an object file in the snapshot, using a unique name in an "objects" subdir.
+    void recordObjectFile(const char *path);
+    
+    // Records symbol names used in dylibs. Does not store anything in the snapshot.
+    void recordDylibSymbol(ld::dylib::File* dylibFile, const char *name);
+    
+    // Stores an archive (.a) file in the snapshot.
+    void recordArchive(const char *archiveFile);
+    
+    // Copies the framework binary into the snapshot frameworks directory.
+    void recordSubUmbrella(const char *frameworkPath);
+    
+    // Copies the library binary into the snapshot dylibs directory.
+    void recordSubLibrary(const char *dylibPath);
+    
+    // Records arbitrary text messages into a log file in the snapshot.
+    // Used by the assertion failure machienery.
+    void recordAssertionMessage(const char *fmt, ...);
+    
+    // Create the snapshot.
+    // Until this is called the snapshot operates lazily, storing minimal data in memory.
+    // When this is called the snapshot is created and any previously recorded data is
+    // immediately copied. Any subsequent additions to the snapshot are copied immediately.
+    void createSnapshot();
+    
+    // Returns the snapshot root directory.
+    const char *rootDir() { return fRootDir; }
+
+private:
+
+    friend class SnapshotArchiveFileLog;
+    
+    typedef std::vector<void(^)(void)> SnapshotLog;    
+
+    struct strcompclass {
+        bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
+    };
+    typedef std::vector<const char *> StringVector;
+    typedef std::map<const char *, int, strcompclass > DylibMap;
+    typedef std::map<const char *, const char *, strcompclass> PathMap;
+
+    
+    // Write the current contents of the args vector to a file in the snapshot.
+    // If filename is NULL then "link_command" is used.
+    // This is used to write both the original and the "cooked" versions of the link command
+    void writeCommandLine(StringVector &args, const char *filename=NULL, bool includeCWD=false);
+
+    // Construct a path in the snapshot.
+    // buf is a sring buffer in which the path is constructed
+    // subdir is an optional subdirectory, and file is a file name
+    // Constructs the path <snapshot_root>/<subdir>/<file> in buf
+    void buildPath(char *buf, const char *subdir, const char *file);
+
+    // Similar to buildPath(), except this ensures the returned path
+    // does not reference an existing file in the snapshot.
+    // Performs uniquing by appending a count suffex to the path (ie .../file-XX)
+    void buildUniquePath(char *buf, const char *subdir, const char *file);
+    
+    // Copies an arbitrary file to the snapshot. Subdir specifies an optional subdirectory name.
+    // Uses buildUniquePath to construct a unique path. If the result path is needed by the caller
+    // then a path buffer can be supplied in buf. Otherwise an internal buffer is used.
+    void copyFileToSnapshot(const char *sourcePath, const char *subdir, char *buf=NULL);
+    
+    // Convert a full path to snapshot relative by constructing an interior pointer at the right offset.
+    const char *snapshotRelativePath(const char *path) { return path+strlen(fRootDir)+1; }
+    
+    // returns true if the snapshot has not been created (by createSnapshot()) yet
+    bool isLazy() { return fRootDir == NULL; }
+
+    void addFrameworkArg(const char *framework);
+    void addDylibArg(const char *dylib);
+
+    SnapshotLog fLog;           // log of events that recorded data in a snapshot prior to createSnapshot()
+    bool fRecordArgs;           // record command line 
+    bool fRecordObjects;        // record .o files 
+    bool fRecordDylibSymbols;   // record referenced dylib/framework symbols
+    bool fRecordArchiveFiles;   // record .a files
+    bool fRecordUmbrellaFiles;  // record re-exported sub frameworks/dylibs
+    bool fRecordDataFiles;      // record other data files
+    bool fFrameworkArgAdded;
+
+    const char *fSnapshotLocation; // parent directory of frootDir
+    const char *fSnapshotName;    // a string to use in constructing the snapshot name
+    char *fRootDir;             // root directory of the snapshot
+    int fFilelistFile;          // file descriptor to the open text file used for the -filelist
+
+    StringVector fRawArgs;      // stores the raw command line args
+    StringVector fArgs;         // stores the "cooked" command line args
+    PathMap fPathMap;           // mapping of original paths->snapshot paths for copied files
+    
+    DylibMap fDylibSymbols;    // map of dylib names to string vector containing referenced symbol names
+    StringVector *fCopiedArchives;  // vector of .a files that have been copied to the snapshot
+};
+
+#endif
index 66ff3588955c46a45743abf88cc503183ac7b4f7..406556a501dc902c79162d2b540fc2849c7ad380 100644 (file)
@@ -34,6 +34,8 @@
 #include <unistd.h>
 #include <assert.h>
 
+#include <iostream>
+#include <sstream>
 #include <string>
 #include <map>
 #include <set>
@@ -57,14 +59,12 @@ namespace tool {
 // HACK, I can't find a way to pass values in the compare classes (e.g. ContentFuncs)
 // so use global variable to pass info.
 static ld::IndirectBindingTable*       _s_indirectBindingTable = NULL;
-bool                                                                           SymbolTable::_s_doDemangle = false;
 
 
 SymbolTable::SymbolTable(const Options& opts, std::vector<const ld::Atom*>& ibt) 
-       : _options(opts), _cstringTable(6151), _indirectBindingTable(ibt), _hasExternalTentativeDefinitions(false)  
+       : _options(opts), _cstringTable(6151), _indirectBindingTable(ibt), _hasExternalTentativeDefinitions(false)
 {  
        _s_indirectBindingTable = this;
-       _s_doDemangle = _options.demangleSymbols();
 }
 
 
@@ -119,251 +119,295 @@ bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom* left, const ld
 }
 
 
+void SymbolTable::addDuplicateSymbol(const char *name, const ld::Atom *atom)
+{
+    // Look up or create the file list for name.
+    DuplicateSymbols::iterator symbolsIterator = _duplicateSymbols.find(name);
+    DuplicatedSymbolAtomList *atoms = NULL;
+    if (symbolsIterator != _duplicateSymbols.end()) {
+        atoms = symbolsIterator->second;
+    } else {
+        atoms = new std::vector<const ld::Atom *>;
+        _duplicateSymbols.insert(std::pair<const char *, DuplicatedSymbolAtomList *>(name, atoms));
+    }
+    
+    // check if file is already in the list, add it if not
+    bool found = false;
+    for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !found && it != atoms->end(); it++)
+        if (strcmp((*it)->file()->path(), atom->file()->path()) == 0)
+            found = true;
+    if (!found)
+        atoms->push_back(atom);
+}
 
-bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
+void SymbolTable::checkDuplicateSymbols() const
 {
-       bool useNew = true;
-       bool checkVisibilityMismatch = false;
-       assert(newAtom.name() != NULL);
-       const char* name = newAtom.name();
-       IndirectBindingSlot slot = this->findSlotForName(name);
-       const ld::Atom* existingAtom = _indirectBindingTable[slot];
-       //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
-       if ( existingAtom != NULL ) {
-               assert(&newAtom != existingAtom);
-               switch ( existingAtom->definition() ) {
-                       case ld::Atom::definitionRegular:
-                               switch ( newAtom.definition() ) {
-                                       case ld::Atom::definitionRegular:
-                                               if ( existingAtom->combine() == ld::Atom::combineByName ) {
-                                                       if ( newAtom.combine() == ld::Atom::combineByName ) {
-                                                               // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
-                                                               const bool existingIsLTO = (existingAtom->contentType() == ld::Atom::typeLTOtemporary);
-                                                               const bool newIsLTO = (newAtom.contentType() == ld::Atom::typeLTOtemporary);
-                                                               if ( existingIsLTO != newIsLTO ) {
-                                                                       useNew = existingIsLTO;
-                                                               }
-                                                               else {
-                                                                       // both weak, prefer non-auto-hide one
-                                                                       if ( newAtom.autoHide() != existingAtom->autoHide() ) {
-                                                                               // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
-                                                                               useNew = existingAtom->autoHide();
-                                                                               // don't check for visibility mismatch
-                                                                       }
-                                                                       else if ( newAtom.autoHide() && existingAtom->autoHide() ) {
-                                                                               // both have auto-hide, so use one with greater alignment
-                                                                               useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
-                                                                       }
-                                                                       else {
-                                                                               // neither auto-hide, check visibility
-                                                                               if ( newAtom.scope() != existingAtom->scope() ) {
-                                                                                       // <rdar://problem/8304984> use more visible weak def symbol
-                                                                                       useNew = (newAtom.scope() == ld::Atom::scopeGlobal);
-                                                                               }
-                                                                               else {
-                                                                                       // both have same visibility, use one with greater alignment
-                                                                                       useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
-                                                                               }
-                                                                       }
-                                                               }
-                                                       }
-                                                       else {
-                                                               // existing weak, new is not-weak
-                                                               useNew = true;
-                                                       }
+    bool foundDuplicate = false;
+    for (DuplicateSymbols::const_iterator symbolIt = _duplicateSymbols.begin(); symbolIt != _duplicateSymbols.end(); symbolIt++) {
+        DuplicatedSymbolAtomList *atoms = symbolIt->second;
+        bool reportDuplicate;
+        if (_options.deadCodeStrip()) {
+            // search for a live atom
+            reportDuplicate = false;
+            for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !reportDuplicate && it != atoms->end(); it++) {
+                if ((*it)->live())
+                    reportDuplicate = true;
+            }
+        } else {
+            reportDuplicate = true;
+        }
+        if (reportDuplicate) {
+            foundDuplicate = true;
+            fprintf(stderr, "duplicate symbol %s in:\n", symbolIt->first);
+            for (DuplicatedSymbolAtomList::iterator atomIt = atoms->begin(); atomIt != atoms->end(); atomIt++) {
+                fprintf(stderr, "    %s\n", (*atomIt)->file()->path());
+            }
+        }
+    }
+    if (foundDuplicate)
+        throwf("%d duplicate symbol%s", (int)_duplicateSymbols.size(), _duplicateSymbols.size()==1?"":"s");
+}
+
+// AtomPicker encapsulates the logic for picking which atom to use when adding an atom by name results in a collision
+class NameCollisionResolution {
+public:
+       NameCollisionResolution(const ld::Atom& a, const ld::Atom& b, bool ignoreDuplicates, const Options& options) : _atomA(a), _atomB(b), _options(options), _reportDuplicate(false), _ignoreDuplicates(ignoreDuplicates) {
+               pickAtom();
+       }
+       
+       // Returns which atom to use
+       const ld::Atom& chosen() { return *_chosen; }
+       bool choseAtom(const ld::Atom& atom) { return _chosen == &atom; }
+
+       // Returns true if the two atoms should be reported as a duplicate symbol
+       bool reportDuplicate()  { return _reportDuplicate; }
+       
+private:
+       const ld::Atom& _atomA;
+       const ld::Atom& _atomB;
+       const Options& _options;
+       const ld::Atom* _chosen;
+       bool _reportDuplicate;
+       bool _ignoreDuplicates;
+
+       void pickAtom(const ld::Atom& atom) { _chosen = &atom; } // primitive to set which atom is picked
+       void pickAtomA() { pickAtom(_atomA); }  // primitive to pick atom A
+       void pickAtomB() { pickAtom(_atomB); }  // primitive to pick atom B
+       
+       // use atom A if pickA, otherwise use atom B
+       void pickAOrB(bool pickA) { if (pickA) pickAtomA(); else pickAtomB(); }
+       
+       void pickHigherOrdinal() {
+               pickAOrB(_atomA.file()->ordinal() < _atomB.file()->ordinal());
+       }
+       
+       void pickLowerOrdinal() {
+               pickAOrB(_atomA.file()->ordinal() > _atomB.file()->ordinal());
+       }
+       
+       void pickLargerSize() {
+               if (_atomA.size() == _atomB.size())
+                       pickLowerOrdinal();
+               else
+                       pickAOrB(_atomA.size() > _atomB.size());
+       }
+       
+       void pickGreaterAlignment() {
+               pickAOrB(_atomA.alignment().trailingZeros() > _atomB.alignment().trailingZeros());
+       }
+       
+       void pickBetweenRegularAtoms() {
+               if ( _atomA.combine() == ld::Atom::combineByName ) {
+                       if ( _atomB.combine() == ld::Atom::combineByName ) {
+                               // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+                               const bool aIsLTO = (_atomA.contentType() == ld::Atom::typeLTOtemporary);
+                               const bool bIsLTO = (_atomB.contentType() == ld::Atom::typeLTOtemporary);
+                               // <rdar://problem/9183821> always choose mach-o over llvm bit code, otherwise LTO may eliminate the llvm atom
+                               if ( aIsLTO != bIsLTO ) {
+                                       pickAOrB(!aIsLTO);
+                               }
+                               else {
+                                       // both weak, prefer non-auto-hide one
+                                       if ( _atomA.autoHide() != _atomB.autoHide() ) {
+                                               // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+                                               pickAOrB(!_atomA.autoHide());
+                                       }
+                                       else if ( _atomA.autoHide() && _atomB.autoHide() ) {
+                                               // both have auto-hide, so use one with greater alignment
+                                               pickGreaterAlignment();
+                                       }
+                                       else {
+                                               // neither auto-hide, check visibility
+                                               if ( _atomA.scope() != _atomB.scope() ) {
+                                                       // <rdar://problem/8304984> use more visible weak def symbol
+                                                       pickAOrB(_atomA.scope() == ld::Atom::scopeGlobal);
                                                }
                                                else {
-                                                       if ( newAtom.combine() == ld::Atom::combineByName ) {
-                                                               // existing not-weak, new is weak
-                                                               useNew = false;
-                                                       }
-                                                       else {
-                                                               // existing not-weak, new is not-weak
-                                                               if ( newAtom.section().type() == ld::Section::typeMachHeader ) {
-                                                                       warning("ignoring override of built-in symbol %s from %s", newAtom.name(), existingAtom->file()->path());
-                                                                       useNew = true;
-                                                               } 
-                                                               else if ( existingAtom->section().type() == ld::Section::typeMachHeader ) {
-                                                                       warning("ignoring override of built-in symbol %s from %s", newAtom.name(), newAtom.file()->path());
-                                                                       useNew = false;
-                                                               } 
-                                                               else {
-                                                                       if ( ignoreDuplicates ) {
-                                                                               useNew = false;
-                                                                               static bool fullWarning = false;
-                                                                               if ( ! fullWarning ) {
-                                                                                       warning("-dead_strip with lazy loaded static (library) archives "
-                                                                                                       "has resulted in a duplicate symbol.  You can change your "
-                                                                                                       "source code to rename symbols to avoid the collision.  "
-                                                                                                       "This will be an error in a future linker.");
-                                                                                       fullWarning = true;
-                                                                               }
-                                                                               warning("duplicate symbol %s originally in %s now lazily loaded from %s",
-                                                                                               SymbolTable::demangle(name), existingAtom->file()->path(), newAtom.file()->path());
-                                                                       }
-                                                                       else {
-                                                                               throwf("duplicate symbol %s in %s and %s", 
-                                                                                               SymbolTable::demangle(name), newAtom.file()->path(), existingAtom->file()->path());
-                                                                       }
-                                                               }
-                                                       }
+                                                       // both have same visibility, use one with greater alignment
+                                                       pickGreaterAlignment();
                                                }
+                                       }
+                               }
+                       }
+                       else {
+                               pickAtomB(); // pick not-weak
+
+                       }
+               }
+               else {
+                       if ( _atomB.combine() == ld::Atom::combineByName ) {
+                               pickAtomA(); // pick not-weak
+
+                       }
+                       else {
+                               // both are not-weak
+                               if ( _atomA.section().type() == ld::Section::typeMachHeader ) {
+                                       pickAtomA();
+                               } 
+                               else if ( _atomB.section().type() == ld::Section::typeMachHeader ) {
+                                       pickAtomB();
+                               } 
+                               else {
+                                       if ( _ignoreDuplicates ) {
+                                               pickLowerOrdinal();
+                                       }
+                                       else {
+                                               _reportDuplicate = true;
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       void pickCommonsMode(const ld::Atom& dylib, const ld::Atom& proxy) {
+               assert(dylib.definition() == ld::Atom::definitionTentative);
+               assert(proxy.definition() == ld::Atom::definitionProxy);
+               switch ( _options.commonsMode() ) {
+                       case Options::kCommonsIgnoreDylibs:
+                               if ( _options.warnCommons() )
+                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
+                                                       proxy.name(), proxy.file()->path(), dylib.file()->path());
+                               pickAtom(dylib);
+                               break;
+                       case Options::kCommonsOverriddenByDylibs:
+                               if ( _options.warnCommons() )
+                                       warning("replacing common symbol %s from %s with true definition from dylib %s",
+                                                       proxy.name(), proxy.file()->path(), dylib.file()->path());
+                               pickAtom(proxy);
+                               break;
+                       case Options::kCommonsConflictsDylibsError:
+                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
+                                          proxy.name(), proxy.file()->path(), dylib.file()->path());
+               }
+       }
+       
+       void pickProxyAtom() {
+               // both atoms are definitionProxy
+               // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
+               if ( _atomA.combine() == ld::Atom::combineByName ) {
+                       pickAtomB();
+               } else if ( _atomB.combine() == ld::Atom::combineByName ) {
+                       pickAtomA();
+               } else {
+                               throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.file()->path(), _atomB.file()->path());
+               }
+       }
+       
+       void pickAtom() {
+               // First, discriminate by definition
+               switch (_atomA.definition()) {
+                       case ld::Atom::definitionRegular:
+                               switch (_atomB.definition()) {
+                                       case ld::Atom::definitionRegular:
+                                               pickBetweenRegularAtoms();
                                                break;
                                        case ld::Atom::definitionTentative:
-                                               // ignore new tentative atom, because we already have a regular one
-                                               useNew = false;
-                                               checkVisibilityMismatch = true;
-                                               if ( newAtom.size() > existingAtom->size() ) {
-                                                       warning("for symbol %s tentative definition of size %llu from %s is "
-                                                                                       "is smaller than the real definition of size %llu from %s",
-                                                                                       newAtom.name(), newAtom.size(), newAtom.file()->path(),
-                                                                                       existingAtom->size(), existingAtom->file()->path());
-                                               }
+                                               pickAtomA();
                                                break;
                                        case ld::Atom::definitionAbsolute:
-                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                               _reportDuplicate = true;
+                                               pickHigherOrdinal();
+                                               break;
                                        case ld::Atom::definitionProxy:
-                                               // ignore external atom, because we already have a one
-                                               useNew = false;
+                                               pickAtomA();
                                                break;
                                }
                                break;
                        case ld::Atom::definitionTentative:
-                               switch ( newAtom.definition() ) {
+                               switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
-                                               // replace existing tentative atom with regular one
-                                               if ( newAtom.section().type() == ld::Section::typeMachHeader ) {
-                                                       // silently replace tentative __dso_handle with real linker created symbol
-                                                       useNew = true;
-                                               }
-                                               else if ( existingAtom->section().type() == ld::Section::typeMachHeader ) {
-                                                       // silently replace tentative __dso_handle with real linker created symbol
-                                                       useNew = false;
-                                               }
-                                               else {
-                                                       checkVisibilityMismatch = true;
-                                                       if ( newAtom.size() < existingAtom->size() ) {
-                                                               warning("for symbol %s tentative definition of size %llu from %s is "
-                                                                                               "being replaced by a real definition of size %llu from %s",
-                                                                                               newAtom.name(), existingAtom->size(), existingAtom->file()->path(),
-                                                                                               newAtom.size(), newAtom.file()->path());
-                                                       }
-                                                       if ( newAtom.section().type() == ld::Section::typeCode ) {
-                                                               warning("for symbol %s tentative (data) defintion from %s is "
-                                                                               "being replaced by code from %s", newAtom.name(), existingAtom->file()->path(),
-                                                                               newAtom.file()->path());
-                                                       }
-                                               }
+                                               pickAtomB();
                                                break;
                                        case ld::Atom::definitionTentative:
-                                               // new and existing are both tentative definitions, use largest
-                                               checkVisibilityMismatch = true;
-                                               if ( newAtom.size() < existingAtom->size() ) {
-                                                       useNew = false;
-                                               } 
-                                               else {
-                                                       if ( newAtom.alignment().trailingZeros() < existingAtom->alignment().trailingZeros() )
-                                                               warning("alignment lost in merging tentative definition %s", newAtom.name());
-                                               }
+                                               pickLargerSize();
                                                break;
                                        case ld::Atom::definitionAbsolute:
-                                               // replace tentative with absolute
-                                               useNew = true;
+                                               pickHigherOrdinal();
                                                break;
                                        case ld::Atom::definitionProxy:
-                                               // a tentative definition and a dylib definition, so commons-mode decides how to handle
-                                               switch ( _options.commonsMode() ) {
-                                                       case Options::kCommonsIgnoreDylibs:
-                                                               if ( _options.warnCommons() )
-                                                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                                                       existingAtom->name(), existingAtom->file()->path(), newAtom.file()->path());
-                                                               useNew = false;
-                                                               break;
-                                                       case Options::kCommonsOverriddenByDylibs:
-                                                               if ( _options.warnCommons() )
-                                                                       warning("replacing common symbol %s from %s with true definition from dylib %s",
-                                                                                       existingAtom->name(), existingAtom->file()->path(), newAtom.file()->path());
-                                                               break;
-                                                       case Options::kCommonsConflictsDylibsError:
-                                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                                                               existingAtom->name(), existingAtom->file()->path(), newAtom.file()->path());
-                                               }
+                                               pickCommonsMode(_atomA, _atomB);
                                                break;
                                }
                                break;
                        case ld::Atom::definitionAbsolute:
-                               switch ( newAtom.definition() ) {
+                               switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
-                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                               _reportDuplicate = true;
+                                               pickHigherOrdinal();
+                                               break;
                                        case ld::Atom::definitionTentative:
-                                               // ignore new tentative atom, because we already have a regular one
-                                               useNew = false;
+                                               pickAtomA();
                                                break;
                                        case ld::Atom::definitionAbsolute:
-                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                               _reportDuplicate = true;
+                                               pickHigherOrdinal();
+                                               break;
                                        case ld::Atom::definitionProxy:
-                                               // ignore external atom, because we already have a one
-                                               useNew = false;
+                                               pickAtomA();
                                                break;
                                }
                                break;
                        case ld::Atom::definitionProxy:
-                               switch ( newAtom.definition() ) {
+                               switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
-                                               // replace external atom with regular one
-                                               useNew = true;
+                                               pickAtomB();
                                                break;
                                        case ld::Atom::definitionTentative:
-                                               // a tentative definition and a dylib definition, so commons-mode decides how to handle
-                                               switch ( _options.commonsMode() ) {
-                                                       case Options::kCommonsIgnoreDylibs:
-                                                               if ( _options.warnCommons() )
-                                                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                                                       newAtom.name(), newAtom.file()->path(), existingAtom->file()->path());
-                                                               break;
-                                                       case Options::kCommonsOverriddenByDylibs:
-                                                               if ( _options.warnCommons() )
-                                                                       warning("replacing defintion of %s from dylib %s with common symbol from %s",
-                                                                                       newAtom.name(), existingAtom->file()->path(), newAtom.file()->path());
-                                                               useNew = false;
-                                                               break;
-                                                       case Options::kCommonsConflictsDylibsError:
-                                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                                                                       newAtom.name(), newAtom.file()->path(), existingAtom->file()->path());
-                                               }
+                                               pickCommonsMode(_atomB, _atomA);
                                                break;
                                        case ld::Atom::definitionAbsolute:
-                                               // replace external atom with absolute one
-                                               useNew = true;
+                                               pickAtomB();
                                                break;
                                        case ld::Atom::definitionProxy:
-                                               // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
-                                               if ( newAtom.combine() == ld::Atom::combineByName ) {
-                                                       useNew = false;
-                                               }
-                                               else {
-                                                       if ( existingAtom->combine() == ld::Atom::combineByName )
-                                                               useNew = true;
-                                                       else
-                                                               throwf("symbol %s exported from both %s and %s\n", name, newAtom.file()->path(), existingAtom->file()->path());
-                                               }
+                                               pickProxyAtom();
                                                break;
                                }
                                break;
-               }       
+               }
        }
-       if ( (existingAtom != NULL) && checkVisibilityMismatch && (newAtom.scope() != existingAtom->scope()) ) {
-               warning("%s has different visibility (%s) in %s and (%s) in %s", 
-                       SymbolTable::demangle(newAtom.name()), (newAtom.scope() == 1 ? "hidden" : "default"), newAtom.file()->path(), (existingAtom->scope()  == 1 ? "hidden" : "default"), existingAtom->file()->path());
+};
+
+bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
+{
+       bool useNew = true;
+       assert(newAtom.name() != NULL);
+       const char* name = newAtom.name();
+       IndirectBindingSlot slot = this->findSlotForName(name);
+       const ld::Atom* existingAtom = _indirectBindingTable[slot];
+       //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+       if ( existingAtom != NULL ) {
+               assert(&newAtom != existingAtom);
+               NameCollisionResolution picker(newAtom, *existingAtom, ignoreDuplicates, _options);
+               if (picker.reportDuplicate()) {
+                       addDuplicateSymbol(name, existingAtom);
+                       addDuplicateSymbol(name, &newAtom);
+               }
+               useNew = picker.choseAtom(newAtom);
        }
        if ( useNew ) {
                _indirectBindingTable[slot] = &newAtom;
                if ( existingAtom != NULL ) {
                        markCoalescedAway(existingAtom);
-//                     if ( fOwner.fInitialLoadsDone ) {
-//                             //fprintf(stderr, "existing %p %s overridden by %p\n", existingAtom, existingAtom->name(), &newAtom);
-//                             fOwner.fAtomsOverriddenByLateLoads.insert(existingAtom);
-//                     }
                }
                if ( newAtom.scope() == ld::Atom::scopeGlobal ) {
                        if ( newAtom.definition() == ld::Atom::definitionTentative ) {
@@ -474,6 +518,16 @@ void SymbolTable::markCoalescedAway(const ld::Atom* atom)
 
 }
 
+
+struct StrcmpSorter {
+               bool operator() (const char* i,const char* j) {
+                       if (i==NULL)
+                               return true;
+                       if (j==NULL)
+                               return false;
+                       return strcmp(i, j)<0;}
+};
+
 void SymbolTable::undefines(std::vector<const char*>& undefs)
 {
        // return all names in _byNameTable that have no associated atom
@@ -483,7 +537,8 @@ void SymbolTable::undefines(std::vector<const char*>& undefs)
                        undefs.push_back(it->first);
        }
        // sort so that undefines are in a stable order (not dependent on hashing functions)
-       std::sort(undefs.begin(), undefs.end());
+       struct StrcmpSorter strcmpSorter;
+       std::sort(undefs.begin(), undefs.end(), strcmpSorter);
 }
 
 
@@ -684,35 +739,6 @@ const ld::Atom* SymbolTable::indirectAtom(IndirectBindingSlot slot) const
        return _indirectBindingTable[slot];
 }
 
-extern "C" char* __cxa_demangle (const char* mangled_name,
-                                  char* buf,
-                                  size_t* n,
-                                  int* status);
-
-const char* SymbolTable::demangle(const char* sym)
-{
-       // only try to demangle symbols if -demangle on command line
-       if ( !_s_doDemangle )
-               return sym;
-
-       // only try to demangle symbols that look like C++ symbols
-       if ( strncmp(sym, "__Z", 3) != 0 )
-               return sym;
-
-       static size_t size = 1024;
-       static char* buff = (char*)malloc(size);
-       int status;
-       
-       char* result = __cxa_demangle(&sym[1], buff, &size, &status); 
-       if ( result != NULL ) {
-               // if demangling succesful, keep buffer for next demangle
-               buff = result;
-               return buff;
-       }
-       return sym;
-}
-
-
 void SymbolTable::printStatistics()
 {
 //     fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n", 
index f352a51c4c6bd8545858f50a7b98f9cffc5253f6..451d0641fc32420bba3f4007c023afa63a7cca77 100644 (file)
@@ -93,6 +93,9 @@ private:
 
        typedef std::map<IndirectBindingSlot, const char*> SlotToName;
        typedef __gnu_cxx::hash_map<const char*, CStringToSlot*, __gnu_cxx::hash<const char*>, CStringEquals> NameToMap;
+    
+    typedef std::vector<const ld::Atom *> DuplicatedSymbolAtomList;
+    typedef std::map<const char *, DuplicatedSymbolAtomList * > DuplicateSymbols;
        
 public:
 
@@ -126,17 +129,24 @@ public:
        byNameIterator          begin()                                                         { return byNameIterator(_byNameTable.begin(),_indirectBindingTable); }
        byNameIterator          end()                                                           { return byNameIterator(_byNameTable.end(),_indirectBindingTable); }
        void                            printStatistics();
-       static const char*              demangle(const char* sym);
        
        // from ld::IndirectBindingTable
        virtual const char*                     indirectName(IndirectBindingSlot slot) const;
        virtual const ld::Atom*         indirectAtom(IndirectBindingSlot slot) const;
+    
+    // Prints the duplicated symbols to stderr and throws. Only valid to call if hasDuplicateSymbols() returns true.
+    void                checkDuplicateSymbols() const;
+
 
 private:
        bool                                    addByName(const ld::Atom& atom, bool ignoreDuplicates);
        bool                                    addByContent(const ld::Atom& atom);
        bool                                    addByReferences(const ld::Atom& atom);
        void                                    markCoalescedAway(const ld::Atom* atom);
+    
+    // Tracks duplicated symbols. Each call adds file to the list of files defining symbol.
+    // The file list is uniqued per symbol, so calling multiple times for the same symbol/file pair is permitted.
+    void                    addDuplicateSymbol(const char *symbol, const ld::Atom* atom);
 
        const Options&                                  _options;
        NameToSlot                                              _byNameTable;
@@ -154,7 +164,7 @@ private:
        std::vector<const ld::Atom*>&   _indirectBindingTable;
        bool                                                    _hasExternalTentativeDefinitions;
        
-       static bool                                             _s_doDemangle;
+    DuplicateSymbols                _duplicateSymbols;
 
 };
 
diff --git a/src/ld/code-sign-blobs/blob.cpp b/src/ld/code-sign-blobs/blob.cpp
new file mode 100644 (file)
index 0000000..5b02f32
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// blob - generic extensible binary blob frame
+//
+#include "blob.h"
+
+namespace Security {
+
+
+//
+// Content access and validation calls
+//
+char *BlobCore::stringAt(Offset offset)
+{
+       char *s = at<char>(offset);
+       if (offset < this->length() && memchr(s, 0, this->length() - offset))
+               return s;
+       else
+               return NULL;
+}
+
+const char *BlobCore::stringAt(Offset offset) const
+{
+       const char *s = at<const char>(offset);
+       if (offset < this->length() && memchr(s, 0, this->length() - offset))
+               return s;
+       else
+               return NULL;
+}
+
+
+//
+// Read a blob from a standard file stream.
+// Reads in one pass, so it's suitable for transmission over pipes and networks.
+// The blob is allocated with malloc(3).
+// On error, sets errno and returns NULL; in which case the input stream may
+// be partially consumed.
+//
+BlobCore *BlobCore::readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize)
+{
+       BlobCore header;
+       if (::pread(fd, &header, sizeof(header), offset) == sizeof(header))
+               if (header.validateBlob(magic, minSize, maxSize))
+                       if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+                               memcpy(blob, &header, sizeof(header));
+                               size_t remainder = header.length() - sizeof(header);
+                               if (::pread(fd, blob+1, remainder, offset + sizeof(header)) == ssize_t(remainder))
+                                       return blob;
+                               free(blob);
+                               errno = EINVAL;
+                       }
+       return NULL;
+}
+
+BlobCore *BlobCore::readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize)
+{
+       BlobCore header;
+       if (::read(fd, &header, sizeof(header)) == sizeof(header))
+               if (header.validateBlob(magic, minSize, maxSize))
+                       if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+                               memcpy(blob, &header, sizeof(header));
+                               size_t remainder = header.length() - sizeof(header);
+                               if (::read(fd, blob+1, remainder) == ssize_t(remainder))
+                                       return blob;
+                               free(blob);
+                               errno = EINVAL;
+                       }
+       return NULL;
+}
+
+BlobCore *BlobCore::readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize)
+{
+       BlobCore header;
+       if (::fread(&header, sizeof(header), 1, file) == 1)
+               if (header.validateBlob(magic, minSize, maxSize))
+                       if (BlobCore *blob = (BlobCore *)malloc(header.length())) {
+                               memcpy(blob, &header, sizeof(header));
+                               if (::fread(blob+1, header.length() - sizeof(header), 1, file) == 1)
+                                       return blob;
+                               free(blob);
+                               errno = EINVAL;
+                       }
+       return NULL;
+}
+
+
+//
+// BlobWrappers
+//
+BlobWrapper *BlobWrapper::alloc(size_t length, Magic magic /* = _magic */)
+{
+       size_t wrapLength = length + sizeof(BlobCore);
+       BlobWrapper *w = (BlobWrapper *)malloc(wrapLength);
+       w->BlobCore::initialize(magic, wrapLength);
+       return w;
+}
+
+BlobWrapper *BlobWrapper::alloc(const void *data, size_t length, Magic magic /* = _magic */)
+{
+       BlobWrapper *w = alloc(length, magic);
+       memcpy(w->data(), data, w->length());
+       return w;
+}
+
+
+}      // Security
diff --git a/src/ld/code-sign-blobs/blob.h b/src/ld/code-sign-blobs/blob.h
new file mode 100644 (file)
index 0000000..db18746
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+//
+// blob - generic extensible binary blob frame
+//
+// To define a new type of binary blob:
+//   class MyBlob : public Blob<MyBlob, magic number> { ... }
+// Pick a unique magic number (32-bit). Blobs are understood to be a MyBlob
+// header possibly followed by more data as a contiguous memory area. Length
+// is overall (including the header), so a fixed-size blob would have length
+// sizeof(MyBlob). Both length and magic are stored in NBO.
+//
+// You are highly encouraged to follow these rules:
+//     Store all integers in NBO, including offsets.
+//  Use internal offsets to "point to" dynamically-sized elements past the
+//   header (using the at<Type>(offset) method for access).
+//  Don't use pointers in your blob.
+// If you follow those rules, your blobs will be fully relocatable, byte-order
+// independent, and generally spreading happiness around your code.
+//
+#ifndef _H_BLOB
+#define _H_BLOB
+
+#include "endian.h"
+#include "memutils.h"
+#include <errno.h>
+
+namespace Security {
+
+enum {
+       // CodeDirectory slot numbers, used to index the EmbeddedSignatureBlob (from codedirectory.h, internal)
+       cdRequirementsSlot = 2                                          // embedded signature: internal requirements
+};
+
+enum {
+       // Code Signing magic blob types (from <Security/CSCommonPriv.h>)
+    kSecCodeMagicRequirement = 0xfade0c00,      /* single requirement */
+    kSecCodeMagicRequirementSet = 0xfade0c01,   /* requirement set */
+    kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
+       
+       kSecCodeMagicDRList = 0xfade0c05 
+};
+
+enum {
+       // from CSCommon.h
+       kSecDesignatedRequirementType = 3                       /* designated requirement */
+};
+
+//
+// All blobs in memory have this form.
+// You can have polymorphic memory blobs (C style) using different magics numbers.
+//
+class BlobCore {
+public:
+       typedef uint32_t Offset;
+       typedef uint32_t Magic;
+
+       Magic magic() const { return mMagic; }
+       size_t length() const { return mLength; }
+       
+       void initialize(Magic mag, size_t len = 0)
+       { mMagic = mag; mLength = len; }
+       
+       bool validateBlob(Magic magic, size_t minSize = 0, size_t maxSize = 0) const;
+
+       template <class T, class Offset>
+       T *at(Offset offset)
+       { return LowLevelMemoryUtilities::increment<T>(this, offset); }
+       
+       template <class T, class Offset>
+       const T *at(Offset offset) const
+       { return LowLevelMemoryUtilities::increment<const T>(this, offset); }
+       
+       template <class Offset1, class Offset2>
+       bool contains(Offset1 offset, Offset2 size) const
+       { return offset >= 0 && size_t(offset) >= sizeof(BlobCore) && (size_t(offset) + size) <= this->length(); }
+       
+       template <class Base, class Offset>
+       bool contains(Base *ptr, Offset size) const
+       { return contains(LowLevelMemoryUtilities::difference(ptr, this), size); }
+
+       char *stringAt(Offset offset);
+       const char *stringAt(Offset offset) const;
+
+       void *data()                                            { return this; }
+       const void *data() const                        { return this; }
+       void length(size_t size)                        { mLength = size; }
+
+       template <class BlobType>
+       bool is() const { return magic() == BlobType::typeMagic; }
+       
+       static BlobCore *readBlob(std::FILE *file)      { return readBlob(file, 0, 0, 0); }
+       static BlobCore *readBlob(int fd)                       { return readBlob(fd, 0, 0, 0); }
+       
+protected:
+       static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize); // streaming
+       static BlobCore *readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize); // streaming
+       static BlobCore *readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize); // pread(2)@offset
+       
+protected:
+       Endian<uint32_t> mMagic;
+       Endian<uint32_t> mLength;
+};
+
+
+// basic validation helper
+inline bool BlobCore::validateBlob(Magic mag, size_t minSize /* = 0 */, size_t maxSize /* = 0 */) const
+{
+       uint32_t len = this->mLength;
+       if (mag && (mag != this->mMagic)) {
+               errno = EINVAL;
+               return false;
+       }
+       if (minSize ? (len < minSize) : (len < sizeof(BlobCore))) {
+               errno = EINVAL;
+               return false;
+       }
+       if (maxSize && len > maxSize) {
+               errno = ENOMEM;
+               return false;
+       }
+       return true;
+}
+
+
+//
+// Typed Blobs (BlobCores that know their real type and magic)
+//
+template <class BlobType, uint32_t _magic>
+class Blob: public BlobCore {
+public:
+       void initialize(size_t size = 0)        { BlobCore::initialize(_magic, size); }
+       
+       static const Magic typeMagic = _magic;
+       
+       bool validateBlob() const
+       { return BlobCore::validateBlob(_magic, sizeof(BlobType)); }
+       
+       bool validateBlob(size_t extLength) const
+       { return validateBlob() && mLength == extLength; }
+       
+       static BlobType *specific(BlobCore *blob, bool unalloc = false)
+       {
+               if (BlobType *p = static_cast<BlobType *>(blob)) {
+                       if (p->validateBlob())
+                               return p;
+                       if (unalloc)
+                               ::free(p);
+               }
+               return NULL;
+       }
+       
+       static const BlobType *specific(const BlobCore *blob)
+       {
+               const BlobType *p = static_cast<const BlobType *>(blob);
+               if (p && p->validateBlob())
+                       return p;
+               return NULL;
+       }
+       
+       BlobType *clone() const
+       { assert(validateBlob()); return specific(this->BlobCore::clone());     }
+
+       static BlobType *readBlob(int fd)
+       { return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType), 0), true); }
+
+       static BlobType *readBlob(int fd, size_t offset, size_t maxSize = 0)
+       { return specific(BlobCore::readBlob(fd, offset, _magic, sizeof(BlobType), maxSize), true); }
+
+       static BlobType *readBlob(std::FILE *file)
+       { return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType), 0), true); }
+};
+
+
+//
+// A generic blob wrapped around arbitrary (flat) binary data.
+// This can be used to "regularize" plain binary data, so it can be handled
+// as a genuine Blob (e.g. for insertion into a SuperBlob).
+//
+class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
+public:
+       static BlobWrapper *alloc(size_t length, Magic magic = BlobWrapper::typeMagic);
+       static BlobWrapper *alloc(const void *data, size_t length, Magic magic = BlobWrapper::typeMagic);
+       
+       unsigned char dataArea[0];
+       
+       // override data/length to point to the payload (only)
+       void *data() { return dataArea; }
+       const void *data() const { return dataArea; }
+       size_t length() const { return BlobCore::length() - sizeof(BlobCore); }
+};
+
+
+}      // Security
+
+#endif //_H_BLOB
diff --git a/src/ld/code-sign-blobs/endian.h b/src/ld/code-sign-blobs/endian.h
new file mode 100644 (file)
index 0000000..f312e43
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2002-2004 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@
+ */
+
+
+/*
+ * cssm utilities
+ */
+#ifndef _H_ENDIAN
+#define _H_ENDIAN
+
+#include <machine/endian.h>
+#include <libkern/OSByteOrder.h>
+//#include <security_utilities/utilities.h>
+#include "memutils.h"
+
+namespace Security {
+
+
+//
+// Encode/decode operations by type, overloaded.
+// You can use these functions directly, but consider using
+// the higher-level constructs below instead.
+//
+#ifdef __LP64__
+static inline unsigned long h2n(unsigned long v) { return OSSwapHostToBigInt64(v); }
+static inline unsigned long n2h(unsigned long v) { return OSSwapBigToHostInt64(v); }
+static inline unsigned long flip(unsigned long v) { return OSSwapInt64(v); }
+static inline signed long h2n(signed long v) { return OSSwapHostToBigInt64(v); }
+static inline signed long n2h(signed long v) { return OSSwapBigToHostInt64(v); }
+static inline signed long flip(signed long v) { return OSSwapInt64(v); }
+#else
+static inline unsigned long h2n(unsigned long v)       { return htonl(v); }
+static inline unsigned long n2h(unsigned long v)       { return ntohl(v); }
+static inline unsigned long flip(unsigned long v)      { return OSSwapInt32(v); }
+static inline signed long h2n(signed long v)           { return htonl(v); }
+static inline signed long n2h(signed long v)           { return ntohl(v); }
+static inline signed long flip(signed long v)          { return OSSwapInt32(v); }
+#endif
+
+static inline unsigned long long h2n(unsigned long long v) { return OSSwapHostToBigInt64(v); }
+static inline unsigned long long n2h(unsigned long long v) { return OSSwapBigToHostInt64(v); }
+static inline unsigned long long flip(unsigned long long v) { return OSSwapInt64(v); }
+static inline long long h2n(long long v)                       { return OSSwapHostToBigInt64(v); }
+static inline long long n2h(long long v)                       { return OSSwapBigToHostInt64(v); }
+static inline long long flip(long long v)                      { return OSSwapInt64(v); }
+
+static inline unsigned int h2n(unsigned int v)         { return htonl(v); }
+static inline unsigned int n2h(unsigned int v)         { return ntohl(v); }
+static inline unsigned int flip(unsigned int v)                { return OSSwapInt32(v); }
+static inline signed int h2n(int v)                                    { return htonl(v); }
+static inline signed int n2h(int v)                                    { return ntohl(v); }
+static inline signed int flip(int v)                           { return OSSwapInt32(v); }
+
+static inline unsigned short h2n(unsigned short v)     { return htons(v); }
+static inline unsigned short n2h(unsigned short v)     { return ntohs(v); }
+static inline unsigned short flip(unsigned short v)    { return OSSwapInt16(v); }
+static inline signed short h2n(signed short v)         { return htons(v); }
+static inline signed short n2h(signed short v)         { return ntohs(v); }
+static inline signed short flip(signed short v)                { return OSSwapInt16(v); }
+
+static inline unsigned char h2n(unsigned char v)       { return v; }
+static inline unsigned char n2h(unsigned char v)       { return v; }
+static inline unsigned char flip(unsigned char v)      { return v; }
+static inline signed char h2n(signed char v)           { return v; }
+static inline signed char n2h(signed char v)           { return v; }
+static inline signed char flip(signed char v)          { return v; }
+
+
+//
+// Flip pointers
+//
+template <class Base>
+static inline Base *h2n(Base *p)       { return (Base *)h2n(uintptr_t(p)); }
+
+template <class Base>
+static inline Base *n2h(Base *p)       { return (Base *)n2h(uintptr_t(p)); }
+
+
+//
+// In-place fix operations
+//
+template <class Type>
+static inline void h2ni(Type &v)       { v = h2n(v); }
+
+template <class Type>
+static inline void n2hi(Type &v)       { v = n2h(v); }
+
+//
+// Endian<SomeType> keeps NBO values in memory and converts
+// during loads and stores. This presumes that you are using
+// memory blocks thare are read/written/mapped as amorphous byte
+// streams, but want to be byte-order clean using them.
+//
+// The generic definition uses h2n/n2h to flip bytes. Feel free
+// to declare specializations of Endian<T> as appropriate.
+//
+// Note well that the address of an Endian<T> is not an address-of-T,
+// and there is no conversion available.
+//
+template <class Type>
+class Endian {
+public:
+    typedef Type Value;
+    Endian() : mValue(Type(0)) { }
+    Endian(Value v) : mValue(h2n(v)) { }
+    
+    operator Value () const            { return n2h(mValue); }
+    Endian &operator = (Value v)       { mValue = h2n(v); return *this; }
+    
+private:
+    Value mValue;
+};
+
+
+}      // end namespace Security
+
+
+#endif //_H_ENDIAN
diff --git a/src/ld/code-sign-blobs/memutils.h b/src/ld/code-sign-blobs/memutils.h
new file mode 100644 (file)
index 0000000..391ddc1
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2000-2004 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@
+ */
+
+
+//
+// memutils - memory-related low-level utilities for easier living
+//
+#ifndef _H_MEMUTILS
+#define _H_MEMUTILS
+
+//#include <security_utilities/utilities.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <algorithm>
+
+
+//
+// Encapsulate these very sharp tools in a separate (ugly-named) namespace
+//
+namespace Security {
+namespace LowLevelMemoryUtilities {
+
+
+//
+// The default system alignment.
+//
+static const size_t systemAlignment = 4;
+
+
+//
+// Get the local alignment for a type, as used by the acting compiler.
+//
+template <class T>
+inline size_t alignof() { struct { char c; T t; } s; return sizeof(s) - sizeof(T); }
+
+
+//
+// Get the local offset of a field in a (struct or class) type, as layed out
+// by the acting compiler.
+// NB: "offsetof" is a standard-defined macro. Don't use that.
+//
+template <class Type, class Field>
+inline size_t fieldOffsetOf(Field (Type::*field))
+{
+       Type *object = 0;       // we don't REALLY need this, but it's easier to read
+       return uintptr_t(&(object->*field)) - uintptr_t(object);
+}
+
+
+//
+// Round up a size or pointer to an alignment boundary.
+// Alignment must be a power of two; default is default alignment.
+//
+inline size_t alignUp(size_t size, size_t alignment = systemAlignment)
+{
+       return ((size - 1) & ~(alignment - 1)) + alignment;
+}
+
+inline void *alignUp(void *p, size_t alignment = systemAlignment)
+{
+       return reinterpret_cast<void *>(alignUp(uintptr_t(p), alignment));
+}
+
+inline const void *alignUp(const void *p, size_t alignment = systemAlignment)
+{
+       return reinterpret_cast<const void *>(alignUp(uintptr_t(p), alignment));
+}
+
+template <class T>
+inline const T *increment(const void *p, ptrdiff_t offset)
+{ return reinterpret_cast<const T *>(uintptr_t(p) + offset); }
+
+template <class T>
+inline T *increment(void *p, ptrdiff_t offset)
+{ return reinterpret_cast<T *>(uintptr_t(p) + offset); }
+
+inline const void *increment(const void *p, ptrdiff_t offset)
+{ return increment<const void>(p, offset); }
+
+inline void *increment(void *p, ptrdiff_t offset)
+{ return increment<void>(p, offset); }
+
+template <class T>
+inline const T *increment(const void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<const T>(alignUp(p, alignment), offset); }
+
+template <class T>
+inline T *increment(void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<T>(alignUp(p, alignment), offset); }
+
+inline const void *increment(const void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<const void>(p, offset, alignment); }
+
+inline void *increment(void *p, ptrdiff_t offset, size_t alignment)
+{ return increment<void>(p, offset, alignment); }
+
+inline ptrdiff_t difference(const void *p1, const void *p2)
+{ return uintptr_t(p1) - uintptr_t(p2); }
+
+
+} // end namespace LowLevelMemoryUtilities
+} // end namespace Security
+
+#endif //_H_MEMUTILS
diff --git a/src/ld/code-sign-blobs/superblob.h b/src/ld/code-sign-blobs/superblob.h
new file mode 100644 (file)
index 0000000..7fea85e
--- /dev/null
@@ -0,0 +1,249 @@
+//
+// SuperBlob - a typed bag of Blobs
+//
+#ifndef _H_SUPERBLOB
+#define _H_SUPERBLOB
+
+#include "blob.h"
+#include <assert.h>
+#include <utility>
+#include <map>
+
+using namespace std;
+
+namespace Security {
+
+
+//
+// A SuperBlob is a Blob that contains multiple sub-Blobs of varying type.
+// The SuperBlob is contiguous and contains a directory of its sub-blobs.
+// A Maker is included.
+//
+// SuperBlobCore lets you define your own SuperBlob type. To just use a generic
+// SuperBlob, use SuperBlob<> below.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+class SuperBlobCore: public Blob<_BlobType, _magic> {
+public:
+       class Maker; friend class Maker;
+       
+       typedef _Type Type;
+       
+       // echoes from parent BlobCore (the C++ type system is too restrictive here)
+       typedef BlobCore::Offset Offset;
+       template <class BlobType> BlobType *at(Offset offset) { return BlobCore::at<BlobType>(offset); }
+       template <class BlobType> const BlobType *at(Offset offset) const { return BlobCore::at<BlobType>(offset); }
+       
+       void setup(size_t size, unsigned cnt)
+       { this->initialize(size); this->mCount = cnt; }
+
+       struct Index {
+               Endian<Type> type;                      // type of sub-Blob
+               Endian<Offset> offset;          // starting offset
+       };
+       
+       bool validateBlob(size_t maxSize = 0) const;
+       
+       unsigned count() const { return mCount; }
+
+       // access by index number
+       Type type(unsigned n) const { assert(n < mCount); return mIndex[n].type; }
+       const BlobCore *blob(unsigned n) const { assert(n < mCount); Offset off=mIndex[n].offset; return off ? at<const BlobCore>(off) : NULL; }
+
+       template <class BlobType>
+       const BlobType *blob(unsigned n) const { return BlobType::specific(blob(n)); }
+
+       // access by index type (assumes unique types)
+       const BlobCore *find(Type type) const;
+       template <class BlobType>
+       const BlobType *find(Type t) const { return BlobType::specific(find(t)); }
+       
+private:
+       Endian<uint32_t> mCount;                // number of sub-Blobs following
+       Index mIndex[0];                                // <count> IndexSlot structures
+       // followed by sub-Blobs, packed and ordered in an undefined way
+};
+
+
+template <class _BlobType, uint32_t _magic, class _Type>
+inline bool SuperBlobCore<_BlobType, _magic, _Type>::validateBlob(size_t maxSize /* = 0 */) const
+{
+       unsigned cnt = mCount;
+       size_t ixLimit = sizeof(SuperBlobCore) + cnt * sizeof(Index);   // end of index vector
+       if (!BlobCore::validateBlob(_magic, ixLimit, maxSize))
+               return false;
+
+       for (const Index *ix = mIndex + cnt - 1; ix >= mIndex; ix--) {
+               Offset offset = ix->offset;
+               if ( offset == 0 )
+                       continue;                               // offset==0 means unused entry
+               if (offset < ixLimit                                                                                                            // offset not too small
+                       || offset + sizeof(BlobCore) > this->length()                                                   // fits Blob header (including length field)
+                       || offset + at<const BlobCore>(offset)->length() > this->length())              // fits entire blob
+                       return false;
+       }
+       return true;
+}
+
+
+//
+// A generic SuperBlob ready for use. You still need to specify a magic number.
+//
+template <uint32_t _magic, class _Type = uint32_t>
+class SuperBlob : public SuperBlobCore<SuperBlob<_magic, _Type>, _magic, _Type> {
+};
+
+
+template <class _BlobType, uint32_t _magic, class _Type>
+const BlobCore *SuperBlobCore<_BlobType, _magic, _Type>::find(Type t) const
+{
+       for (unsigned slot = 0; slot < mCount; slot++) {
+               if (mIndex[slot].type == t) {
+                       uint32_t off = mIndex[slot].offset;
+                       if ( off == 0 ) 
+                               return NULL;
+                       else
+                               return at<const BlobCore>(off);
+               }
+       }
+       return NULL;    // not found
+}
+
+
+//
+// A SuperBlob::Maker simply assembles multiple Blobs into a single, indexed
+// super-blob. Just add() sub-Blobs by type and call build() to get
+// the result, malloc'ed. A Maker is not reusable.
+// Maker can repeatedly make SuperBlobs from the same (cached) inputs.
+// It can also tell you how big its output will be, given established contents
+// plus (optional) additional sizes of blobs yet to come.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+class SuperBlobCore<_BlobType, _magic, _Type>::Maker {
+public:
+       Maker() { }
+       
+       Maker(const Maker &src)
+       {
+               for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
+                       mPieces.insert(make_pair(it->first, it->second->clone()));
+       }
+
+       ~Maker()
+       {
+               for (typename BlobMap::iterator it = mPieces.begin(); it != mPieces.end(); ++it)
+                       ::free(it->second);
+       }
+       
+       void add(Type type, BlobCore *blob);            // takes ownership of blob
+       void add(const _BlobType *blobs);                       // copies all blobs
+       void add(const Maker &maker);                           // ditto
+       
+       size_t size(size_t size1 = 0, ...) const;       // size with optional additional blob sizes
+       _BlobType *make() const;                                        // create (malloc) and return SuperBlob
+       _BlobType *operator () () const { return make(); }
+
+private:
+       typedef std::map<Type, BlobCore *> BlobMap;
+       BlobMap mPieces;
+};
+
+
+//
+// Add a Blob to a SuperBlob::Maker.
+// This takes ownership of the blob, which must have been malloc'ed.
+// Any previous value set for this Type will be freed immediately.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(Type type, BlobCore *blob)
+{
+       pair<typename BlobMap::iterator, bool> r = mPieces.insert(make_pair(type, blob));
+       if (!r.second) {        // already there
+               //secdebug("superblob", "Maker %p replaces type=%d", this, type);
+               ::free(r.first->second);
+               r.first->second = blob;
+       }
+}
+
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const _BlobType *blobs)
+{
+       for (uint32_t ix = 0; ix < blobs->mCount; ix++)
+               this->add(blobs->mIndex[ix].type, blobs->blob(ix)->clone());
+}
+
+template <class _BlobType, uint32_t _magic, class _Type>
+void SuperBlobCore<_BlobType, _magic, _Type>::Maker::add(const Maker &maker)
+{
+       for (typename BlobMap::const_iterator it = maker.mPieces.begin(); it != maker.mPieces.end(); ++it)
+               this->add(it->first, it->second->clone());
+}
+
+
+//
+// Calculate the size the new SuperBlob would have, given the contents of the Maker
+// so far, plus additional blobs with the sizes given.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+size_t SuperBlobCore<_BlobType, _magic, _Type>::Maker::size(size_t size1, ...) const
+{
+       // count established blobs
+       unsigned count = mPieces.size();
+       size_t total = 0;
+       for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
+               if ( it->second != NULL )
+                       total += (it->second->length() + 3) & (-4); // 4-byte align each element
+       }
+
+       // add preview blob sizes to calculation (if any)
+       if (size1) {
+               va_list args;
+               va_start(args, size1);
+               do {
+                       count++;
+                       total += size1;
+                       size1 = va_arg(args, size_t);
+               } while (size1);
+               va_end(args);
+       }
+
+       return sizeof(SuperBlobCore) + count * sizeof(Index) + total;
+}
+
+
+//
+// Finish SuperBlob construction and return the new, malloc'ed, SuperBlob.
+// This can be done repeatedly.
+//
+template <class _BlobType, uint32_t _magic, class _Type>
+_BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
+{
+       Offset pc = sizeof(SuperBlobCore) + mPieces.size() * sizeof(Index);
+       Offset total = size();
+       _BlobType *result = (_BlobType *)calloc(1, total);
+       if (!result)
+               throw ENOMEM;
+       result->setup(total, mPieces.size());
+       unsigned n = 0;
+       for (typename BlobMap::const_iterator it = mPieces.begin(); it != mPieces.end(); ++it) {
+               result->mIndex[n].type = it->first;
+               BlobCore* b = it->second;
+               if ( b != NULL ) {
+                       result->mIndex[n].offset = pc;
+                       memcpy(result->template at<unsigned char>(pc), b, b->length());
+                       pc += ((b->length() + 3) & (-4)); // 4-byte align each element 
+               }
+               else {
+                       result->mIndex[n].offset = 0;
+               }
+               n++;
+       }
+       //secdebug("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
+       //      this, mPieces.size(), result, total);
+       return result;
+}
+
+
+}      // Security
+
+#endif //_H_SUPERBLOB
index ce49e73463db5ed6418b2d23a0b0bf7c207ccbca..24e9c48bc4aa4c0d47226f4fba643f4c014ec06b 100644 (file)
@@ -67,6 +67,7 @@ extern "C" double log2 ( double );
 #include "InputFiles.h"
 #include "Resolver.h"
 #include "OutputFile.h"
+#include "Snapshot.h"
 
 #include "passes/stubs/make_stubs.h"
 #include "passes/dtrace_dof.h"
@@ -619,6 +620,25 @@ static void getVMInfo(vm_statistics_data_t& info)
        }
 }
 
+
+
+static const char* sOverridePathlibLTO = NULL;
+
+//
+// This is magic glue that overrides the default behaviour 
+// of lazydylib1.o which is used to lazily load libLTO.dylib.
+//
+extern "C" const char* dyld_lazy_dylib_path_fix(const char* path);
+const char* dyld_lazy_dylib_path_fix(const char* path)
+{
+       if ( sOverridePathlibLTO != NULL )
+               return sOverridePathlibLTO;
+       else
+               return path;
+}
+
+
+
 int main(int argc, const char* argv[])
 {
        const char* archName = NULL;
@@ -632,6 +652,9 @@ int main(int argc, const char* argv[])
                Options options(argc, argv);
                InternalState state(options);
                
+               // allow libLTO to be overridden by command line -lto_library
+               sOverridePathlibLTO = options.overridePathlibLTO();
+               
                // gather vm stats
                if ( options.printStatistics() )
                        getVMInfo(statistics.vmStart);
@@ -649,7 +672,7 @@ int main(int argc, const char* argv[])
                statistics.startResolver = mach_absolute_time();
                ld::tool::Resolver resolver(options, inputFiles, state);
                resolver.resolve();
-                               
+        
                // add dylibs used
                statistics.startDylibs = mach_absolute_time();
                inputFiles.dylibs(state);
@@ -727,7 +750,11 @@ int main(int argc, const char* argv[])
 // implement assert() function to print out a backtrace before aborting
 void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
 {
-       fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
+    Snapshot *snapshot = Snapshot::globalSnapshot;
+    
+    snapshot->setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+    snapshot->createSnapshot();
+       snapshot->recordAssertionMessage("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
 
        void* callStack[128];
        int depth = ::backtrace(callStack, 128);
@@ -745,7 +772,10 @@ void __assert_rtn(const char* func, const char* file, int line, const char* fail
                }
                long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
                fprintf(stderr, "%d  %p  %s + %ld\n", i, callStack[i], symboName, offset);
+               snapshot->recordAssertionMessage("%d  %p  %s + %ld\n", i, callStack[i], symboName, offset);
        }
+    fprintf(stderr, "A linker snapshot was created at:\n\t%s\n", snapshot->rootDir());
+       fprintf(stderr, "ld: Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
        exit(1);
 }
 #endif
index b615046effa1cbec74fbe1fbfee20d1cac0a5267..c33bff681bdac0af35617dd5fdd0457c8670c9fd 100644 (file)
@@ -60,21 +60,93 @@ public:
                virtual void            doFile(const class File&) = 0;
        };
 
-                                                                               File(const char* pth, time_t modTime, uint32_t ord)
-                                                                                       : _path(pth), _modTime(modTime), _ordinal(ord) { }
+       //
+       // ld::File::Ordinal 
+       //
+       // Codifies the rules of ordering input files for symbol precedence. These are:
+       // - Input files listed on the command line are ordered according to their index in the argument list.
+       // - Input files listed in a file list are ordered first at the index of the file list argument, then
+       //   by index in the file list
+       // - Input files extracted from archives are ordered using the ordinal of the archive itself plus the
+       //   index of the object file within the archive
+       // - Indirect dylibs are ordered after all input files derived from the command line, in the order that
+       //   they are discovered.
+       // - The LTO object file is last.
+       //
+       class Ordinal
+       {
+       private:
+               // The actual numeric ordinal. Lower values have higher precedence and a zero value is invalid.
+               // The 64 bit ordinal is broken into 4 16 bit chunks. The high 16 bits are a "partition" that
+               // is used to distinguish major ordinal groups: command line, indirect dylib, LTO.
+               // The remaining chunks are used according to the partition (see below).
+               uint64_t        _ordinal;
+               
+               Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
+               
+               enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff };
+               Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
+                       _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
+               }
+               
+               const uint16_t  partition() const               { return (_ordinal>>48)&0xffff; }
+               const uint16_t  majorIndex() const              { return (_ordinal>>32)&0xffff; }
+               const uint16_t  minorIndex() const              { return (_ordinal>>16)&0xffff; }
+               const uint16_t  counter() const                 { return (_ordinal>>00)&0xffff; }
+               
+               const Ordinal nextMajorIndex()          const { assert(majorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<32)); }
+               const Ordinal nextMinorIndex()          const { assert(minorIndex() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<16)); }
+               const Ordinal nextCounter()             const { assert(counter() < 0xffff); return Ordinal(_ordinal+((uint64_t)1<<0)); }
+               
+       public:
+               Ordinal() : _ordinal(0) {};
+               
+               static const Ordinal NullOrdinal()              { return Ordinal((uint64_t)0); }
+               
+               const bool validOrdinal() const { return _ordinal != 0; }
+               
+               bool operator ==(const Ordinal& rhs) const { return _ordinal == rhs._ordinal; }
+               bool operator !=(const Ordinal& rhs) const {    return _ordinal != rhs._ordinal; }
+               bool operator < (const Ordinal& rhs) const { return _ordinal < rhs._ordinal; }
+               bool operator > (const Ordinal& rhs) const { return _ordinal > rhs._ordinal; }
+               
+               // For ordinals derived from the command line args the partition is ArgListPartition
+               // The majorIndex is the arg index that pulls in the file, file list, or archive.
+               // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
+               // The counter is used for .a files and the value is the index of the object in the archive.
+               // Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
+               static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); };
+               const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
+               const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); }
+               
+               // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
+               static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); }
+               const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
+               
+               // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
+               static const ld::File::Ordinal LTOOrdinal()                     { return Ordinal(LTOPartition, 0, 0, 0); }
+       };
+       
+       typedef enum { Reloc, Dylib, Archive, Other } Type;
+       
+                                                                               File(const char* pth, time_t modTime, Ordinal ord, Type type)
+                                                                                       : _path(pth), _modTime(modTime), _ordinal(ord), _type(type) { }
        virtual                                                         ~File() {}
                        const char*                                     path() const                    { return _path; }
                        time_t                                          modificationTime() const{ return _modTime; }
-                       uint32_t                                        ordinal() const                 { return _ordinal; }
+       Ordinal                                                         ordinal() const                 { return _ordinal; }
        virtual bool                                            forEachAtom(AtomHandler&) const = 0;
        virtual bool                                            justInTimeforEachAtom(const char* name, AtomHandler&) const = 0;
        virtual ObjcConstraint                          objCConstraint() const                  { return objcConstraintNone; }
        virtual uint32_t                                        cpuSubType() const              { return 0; }
        virtual uint32_t                                        subFileCount() const    { return 1; }
+    bool                                                               fileExists() const     { return _modTime != 0; }
+       Type                                                            type() const { return _type; }
 private:
        const char*                                                     _path;
        time_t                                                          _modTime;
-       uint32_t                                                        _ordinal;
+       const Ordinal                                           _ordinal;
+       const Type                                                      _type;
 };
 
 
@@ -82,9 +154,11 @@ private:
 // minumum OS versions
 //
 enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
-                                               mac10_6=0x000A0600, mac10_7=0x000A0700 };
+                                               mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
+                                               mac10_Future=0x10000000 };
 enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100, 
-                                               iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000 };
+                                               iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
+                                               iOS_Future=0x10000000};
  
 namespace relocatable {
        //
@@ -92,8 +166,6 @@ namespace relocatable {
        //
        // Abstract base class for object files the linker processes.
        // 
-       // objcReplacementClasses() is reflects if the file was compiled for fix-and-continue
-       //
        // debugInfo() returns if the object file contains debugger information (stabs or dwarf).
        //
        // stabs() lazily creates a vector of Stab objects for each atom
@@ -118,10 +190,9 @@ namespace relocatable {
                        const char*                     string;
                };
 
-                                                                                       File(const char* pth, time_t modTime, uint32_t ord)
-                                                                                               : ld::File(pth, modTime, ord) { }
+                                                                                       File(const char* pth, time_t modTime, Ordinal ord)
+                                                                                               : ld::File(pth, modTime, ord, Reloc) { }
                virtual                                                         ~File() {}
-               virtual bool                                            objcReplacementClasses() const = 0;
                virtual DebugInfoKind                           debugInfo() const = 0;
                virtual const char*                                     debugInfoPath() const { return path(); }
                virtual time_t                                          debugInfoModificationTime() const { return modificationTime(); }
@@ -149,8 +220,8 @@ namespace dylib {
                        virtual File*           findDylib(const char* installPath, const char* fromPath) = 0;
                };
                        
-                                                                                       File(const char* pth, time_t modTime, uint32_t ord)
-                                                                                               : ld::File(pth, modTime, ord), _dylibInstallPath(NULL),
+                                                                                       File(const char* pth, time_t modTime, Ordinal ord)
+                                                                                               : ld::File(pth, modTime, ord, Dylib), _dylibInstallPath(NULL),
                                                                                                _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0),
                                                                                                _explicitlyLinked(false), _implicitlyLinked(false),
                                                                                                _lazyLoadedDylib(false), _forcedWeakLinked(false), _reExported(false),
@@ -163,6 +234,7 @@ namespace dylib {
                                bool                                            explicitlyLinked() const        { return _explicitlyLinked; }
                                void                                            setImplicitlyLinked()           { _implicitlyLinked = true; }
                                bool                                            implicitlyLinked() const        { return _implicitlyLinked; }
+                               
                                // attributes of how dylib will be used when linked
                                void                                            setWillBeLazyLoadedDylb()               { _lazyLoadedDylib = true; }
                                bool                                            willBeLazyLoadedDylib() const   { return _lazyLoadedDylib; }
@@ -185,6 +257,7 @@ namespace dylib {
                virtual bool                                            hasWeakDefinition(const char* name) const = 0;
                virtual bool                                            hasPublicInstallName() const = 0;
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
+               virtual const void*                                     codeSignatureDR() const = 0;
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
@@ -210,8 +283,8 @@ namespace archive {
        class File : public ld::File
        {
        public:
-                                                                                       File(const char* pth, time_t modTime, uint32_t ord)
-                                                                                               : ld::File(pth, modTime, ord) { }
+                                                                                       File(const char* pth, time_t modTime, Ordinal ord)
+                                                                                               : ld::File(pth, modTime, ord, Archive) { }
                virtual                                                         ~File() {}
                virtual bool                                            justInTimeDataOnlyforEachAtom(const char* name, AtomHandler&) const = 0;
        };
@@ -325,6 +398,9 @@ struct Fixup
                                        kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
                                        // lazy binding
                                        kindLazyTarget, kindSetLazyOffset,
+                                       // data-in-code markers
+                                       kindDataInCodeStartData, kindDataInCodeStartJT8, kindDataInCodeStartJT16, 
+                                       kindDataInCodeStartJT32, kindDataInCodeStartJTA32, kindDataInCodeEnd,
                                        // pointer store combinations
                                        kindStoreTargetAddressLittleEndian32,   // kindSetTargetAddress + kindStoreLittleEndian32
                                        kindStoreTargetAddressLittleEndian64,   // kindSetTargetAddress + kindStoreLittleEndian64
@@ -579,7 +655,9 @@ public:
        void                                                                    setSectionStartAddress(uint64_t a) { assert(_mode == modeSectionOffset); _address += a; _mode = modeFinalAddress; }
        uint64_t                                                                sectionOffset() const           { assert(_mode == modeSectionOffset); return _address; }
        uint64_t                                                                finalAddress() const            { assert(_mode == modeFinalAddress); return _address; }
-
+#ifndef NDEBUG
+       bool                                                                    finalAddressMode() const    { return (_mode == modeFinalAddress); }
+#endif
        virtual const File*                                             file() const = 0;
        virtual bool                                                    translationUnitSource(const char** dir, const char** name) const = 0;
        virtual const char*                                             name() const = 0;
@@ -591,6 +669,13 @@ public:
        virtual bool                                                    canCoalesceWith(const Atom& rhs, const class IndirectBindingTable&) const { return false; }
        virtual Fixup::iterator                                 fixupsBegin() const     { return NULL; }
        virtual Fixup::iterator                                 fixupsEnd() const       { return NULL; }
+       bool                                                                    hasFixupsOfKind(Fixup::Kind kind) const {
+               for (ld::Fixup::iterator fit = fixupsBegin(), end=fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->kind == kind ) return true;
+               }
+               return false;
+       }
+       
        virtual UnwindInfo::iterator                    beginUnwind() const { return NULL; }
        virtual UnwindInfo::iterator                    endUnwind() const       { return NULL; }
        virtual LineInfo::iterator                              beginLineInfo() const { return NULL; }
@@ -681,7 +766,7 @@ public:
                                                                                        objcObjectConstraint(ld::File::objcConstraintNone), 
                                                                                        objcDylibConstraint(ld::File::objcConstraintNone), 
                                                                                        cpuSubType(0), 
-                                                                                       allObjectFilesScatterable(true), hasObjcReplacementClasses(false),
+                                                                                       allObjectFilesScatterable(true), 
                                                                                        someObjectFileHasDwarf(false), usingHugeSections(false) { }
                                                                                
        std::vector<FinalSection*>                                      sections;
@@ -697,7 +782,6 @@ public:
        ld::File::ObjcConstraint                                        objcDylibConstraint;
        uint32_t                                                                        cpuSubType;
        bool                                                                            allObjectFilesScatterable;
-       bool                                                                            hasObjcReplacementClasses;
        bool                                                                            someObjectFileHasDwarf;
        bool                                                                            usingHugeSections;
 };
index cf0a05854dcc23e617db67441bcd47caeb0b7470..78d8912043899125d03a58d4babad82e2109d380 100644 (file)
@@ -62,7 +62,7 @@ public:
                                                                                                                return File<A>::validFile(fileContent, fileLength, opts); }
        static File<A>*                                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
-                                                                                                                       uint32_t ordinal, const ParserOptions& opts) {
+                                                                                                                       ld::File::Ordinal ordinal, const ParserOptions& opts) {
                                                                                                                         return new File<A>(fileContent, fileLength, path, mTime,
                                                                                                                                                        ordinal, opts);
                                                                                                                }
@@ -77,7 +77,7 @@ public:
                                                                                                                                const mach_o::relocatable::ParserOptions& opts);
                                                                                                        File(const uint8_t* fileContent, uint64_t fileLength,
                                                                                                                        const char* pth, time_t modTime, 
-                                                                                                                       uint32_t ord, const ParserOptions& opts);
+                                                                                                                       ld::File::Ordinal ord, const ParserOptions& opts);
        virtual                                                                                 ~File() {}
 
        // overrides of ld::File
@@ -98,7 +98,7 @@ private:
        class Entry : ar_hdr
        {
        public:
-               const char*                     name() const;
+               void                            getName(char *, int) const;
                time_t                          modificationTime() const;
                const uint8_t*          content() const;
                uint32_t                        contentSize() const;
@@ -109,6 +109,9 @@ private:
 
        };
 
+       struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint16_t index;};
+       bool                                                                                    loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
+
        class CStringEquals
        {
        public:
@@ -119,8 +122,6 @@ private:
        typedef typename A::P                                                   P;
        typedef typename A::P::E                                                E;
 
-       struct MemberState { ld::relocatable::File* file; bool logged; bool loaded; };
-       
        typedef std::map<const class Entry*, MemberState> MemberToStateMap;
 
        const struct ranlib*                                                    ranlibHashSearch(const char* name) const;
@@ -161,23 +162,21 @@ unsigned int File<A>::Entry::getLongNameSpace() const
 }
 
 template <typename A>
-const char* File<A>::Entry::name() const
+void File<A>::Entry::getName(char *buf, int bufsz) const
 {
        if ( this->hasLongName() ) {
                int len = this->getLongNameSpace();
-               static char longName[256];
-               strncpy(longName, ((char*)this)+sizeof(ar_hdr), len);
-               longName[len] = '\0';
-               return longName;
+               assert(bufsz >= len+1);
+               strncpy(buf, ((char*)this)+sizeof(ar_hdr), len);
+               buf[len] = '\0';
        }
        else {
-               static char shortName[20];
-               strncpy(shortName, this->ar_name, 16);
-               shortName[16] = '\0';
-               char* space = strchr(shortName, ' ');
+               assert(bufsz >= 16+1);
+               strncpy(buf, this->ar_name, 16);
+               buf[16] = '\0';
+               char* space = strchr(buf, ' ');
                if ( space != NULL )
                        *space = '\0';
-               return shortName;
        }
 }
 
@@ -256,7 +255,8 @@ bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const m
        const Entry* const start = (Entry*)&fileContent[8];
        const Entry* const end = (Entry*)&fileContent[fileLength];
        for (const Entry* p=start; p < end; p = p->next()) {
-               const char* memberName = p->name();
+               char memberName[256];
+               p->getName(memberName, sizeof(memberName));
                // skip option table-of-content member
                if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
                        continue;
@@ -270,7 +270,7 @@ bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const m
 
 template <typename A>
 File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth, time_t modTime, 
-                                       uint32_t ord, const ParserOptions& opts)
+                                       ld::File::Ordinal ord, const ParserOptions& opts)
  : ld::archive::File(strdup(pth), modTime, ord),
        _archiveFileContent(fileContent), _archiveFilelength(fileLength), 
        _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL), 
@@ -283,7 +283,9 @@ File<A>::File(const uint8_t fileContent[], uint64_t fileLength, const char* pth,
 
        if ( !_forceLoadAll ) {
                const Entry* const firstMember = (Entry*)&_archiveFileContent[8];
-               if ( (strcmp(firstMember->name(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->name(), SYMDEF) == 0) ) {
+               char memberName[256];
+               firstMember->getName(memberName, sizeof(memberName));
+               if ( (strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0) ) {
                        const uint8_t* contents = firstMember->content();
                        uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
                        _tableOfContents = (const struct ranlib*)&contents[4];
@@ -308,7 +310,8 @@ bool File<x86>::memberHasObjCCategories(const Entry* member) const
        }
        else {
                // i386 uses ObjC1 ABI which has .objc_category* global symbols
-               return false;
+    // <rdar://problem/11342022> strip -S on i386 pulls out .objc_category_name symbols from static frameworks
+               return mach_o::relocatable::hasObjC1Categories(member->content());
        }
 }
 
@@ -325,12 +328,37 @@ bool File<A>::memberHasObjCCategories(const Entry* member) const
 template <typename A>
 typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
 {
+       uint16_t memberIndex = 0;
        // in case member was instantiated earlier but not needed yet
        typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
-       if ( pos != _instantiatedEntries.end() )
-               return pos->second;
-
-       const char* memberName = member->name();
+       if ( pos == _instantiatedEntries.end() ) {
+               // Have to find the index of this member
+               const Entry* start;
+               uint16_t index;
+               if (_instantiatedEntries.size() == 0) {
+                       start = (Entry*)&_archiveFileContent[8];
+                       index = 1;
+               } else {
+                       MemberState &lastKnown = _instantiatedEntries.rbegin()->second;
+                       start = lastKnown.entry->next();
+                       index = lastKnown.index+1;
+               }
+               for (const Entry* p=start; p <= member; p = p->next(), index++) {
+                       MemberState state = {NULL, p, false, false, index};
+                       _instantiatedEntries[p] = state;
+                       if (member == p) {
+                               memberIndex = index;
+                       }
+               }
+       } else {
+               MemberState& state = pos->second;
+               if (state.file)
+                       return state;
+               memberIndex = state.index;
+       }
+       assert(memberIndex != 0);
+       char memberName[256];
+       member->getName(memberName, sizeof(memberName));
        char memberPath[strlen(this->path()) + strlen(memberName)+4];
        strcpy(memberPath, this->path());
        strcat(memberPath, "(");
@@ -344,23 +372,22 @@ typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* mem
                if ( (member->content() + member->contentSize()) > (_archiveFileContent+_archiveFilelength) )
                        throwf("corrupt archive, member contents extends past end of file");                                                                            
                const char* mPath = strdup(memberPath);
-               // offset the ordinals in this mach-o .o file, so that atoms layout in same order as in archive
-               uint32_t memberIndex = ((uint8_t*)member - _archiveFileContent)/sizeof(ar_hdr);
                // see if member is mach-o file
+               ld::File::Ordinal ordinal = this->ordinal().archiveOrdinalWithMemberIndex(memberIndex);
                ld::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(), 
                                                                                                                                        mPath, member->modificationTime(), 
-                                                                                                                                       this->ordinal() + memberIndex, _objOpts);
+                                                                                                                                       ordinal, _objOpts);
                if ( result != NULL ) {
-                       MemberState state = {result, false, false};
+                       MemberState state = {result, member, false, false, memberIndex};
                        _instantiatedEntries[member] = state;
                        return _instantiatedEntries[member];
                }
                // see if member is llvm bitcode file
                result = lto::parse(member->content(), member->contentSize(), 
-                                                               mPath, member->modificationTime(), this->ordinal() + memberIndex, 
+                                                               mPath, member->modificationTime(), 
                                                                _objOpts.architecture, _objOpts.subType, _logAllFiles);
                if ( result != NULL ) {
-                       MemberState state = {result, false, false};
+                       MemberState state = {result, member, false, false, memberIndex};
                        _instantiatedEntries[member] = state;
                        return _instantiatedEntries[member];
                }
@@ -373,6 +400,25 @@ typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* mem
 }
 
 
+template <typename A>
+bool File<A>::loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const
+{
+       bool didSomething = false;
+       if (!state.loaded) {
+               if ( _verboseLoad && !state.logged ) {
+                       va_list list;
+                       va_start(list, format);
+                       vprintf(format, list);
+                       va_end(list);
+                       state.logged = true;
+               }
+               state.loaded = true;
+               didSomething = state.file->forEachAtom(handler);
+       }
+       return didSomething;
+}
+
+
 template <typename A>
 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
 {
@@ -382,19 +428,12 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                const Entry* const start = (Entry*)&_archiveFileContent[8];
                const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
                for (const Entry* p=start; p < end; p = p->next()) {
-                       const char* memberName = p->name();
+                       char memberName[256];
+                       p->getName(memberName, sizeof(memberName));
                        if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
                                continue;
                        MemberState& state = this->makeObjectFileForMember(p);
-                       if ( _verboseLoad ) {
-                               if ( _forceLoadThis )
-                                       printf("-force_load forced load of %s(%s)\n", this->path(), memberName);
-                               else
-                                       printf("-all_load forced load of %s(%s)\n", this->path(), memberName);
-                               state.logged = true;
-                       }
-                       didSome |= state.file->forEachAtom(handler);
-                       state.loaded = true;
+                       didSome |= loadMember(state, handler, "%s forced load of %s(%s)\n", _forceLoadThis ? "-force_load" : "-all_load", this->path(), memberName);
                }
        }
        else if ( _forceLoadObjC ) {
@@ -403,33 +442,28 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                        if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
                                const Entry* member = (Entry*)&_archiveFileContent[E::get32(it->second->ran_off)];
                                MemberState& state = this->makeObjectFileForMember(member);
-                               if ( _verboseLoad && !state.logged ) {
-                                       printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                       state.logged = true;
-                               }
-                               if ( ! state.loaded ) {
-                                       didSome |= state.file->forEachAtom(handler);
-                                       state.loaded = true;
-                               }
+                               char memberName[256];
+                               member->getName(memberName, sizeof(memberName));
+                               didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
                        }
                }
                // ObjC2 has no symbols in .o files with categories but not classes, look deeper for those
                const Entry* const start = (Entry*)&_archiveFileContent[8];
                const Entry* const end = (Entry*)&_archiveFileContent[_archiveFilelength];
                for (const Entry* member=start; member < end; member = member->next()) {
-                       // only look at files not already instantiated
-                       if ( _instantiatedEntries.count(member) == 0 ) {
-                               //fprintf(stderr, "checking member %s\n", member->name());
+                       char mname[256];
+                       member->getName(mname, sizeof(mname));
+                       // skip table-of-content member
+                       if ( (member==start) && ((strcmp(mname, SYMDEF_SORTED) == 0) || (strcmp(mname, SYMDEF) == 0)) )
+                               continue;
+                       MemberState& state = this->makeObjectFileForMember(member);
+                       // only look at files not already loaded
+                       if ( ! state.loaded ) {
                                if ( this->memberHasObjCCategories(member) ) {
                                        MemberState& state = this->makeObjectFileForMember(member);
-                                       if ( _verboseLoad && !state.logged ) {
-                                               printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
-                                               state.logged = true;
-                                       }
-                                       if ( ! state.loaded ) {
-                                               didSome |= state.file->forEachAtom(handler);
-                                               state.loaded = true;
-                                       }
+                                       char memberName[256];
+                                       member->getName(memberName, sizeof(memberName));
+                                       didSome |= loadMember(state, handler, "-ObjC forced load of %s(%s)\n", this->path(), memberName);
                                }
                        }
                }
@@ -449,15 +483,9 @@ bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han
        if ( result != NULL ) {
                const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
                MemberState& state = this->makeObjectFileForMember(member);
-               // only call handler for each member once
-               if ( ! state.loaded && !state.logged ) {
-                       if ( _verboseLoad ) {
-                               printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
-                               state.logged = true;
-                       }
-                       state.loaded = true;
-                       return state.file->forEachAtom(handler);
-               }
+               char memberName[256];
+               member->getName(memberName, sizeof(memberName));
+               return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
        }
        //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
        return false;
@@ -499,12 +527,9 @@ bool File<A>::justInTimeDataOnlyforEachAtom(const char* name, ld::File::AtomHand
                        CheckIsDataSymbolHandler checker(name);
                        state.file->forEachAtom(checker);
                        if ( checker.symbolIsDataDefinition() ) {
-                               if ( _verboseLoad && !state.logged ) {
-                                       printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
-                                       state.logged = true;
-                               }
-                               state.loaded = true;
-                               return state.file->forEachAtom(handler);
+                               char memberName[256];
+                               member->getName(memberName, sizeof(memberName));
+                               return loadMember(state, handler, "%s forced load of %s(%s)\n", name, this->path(), memberName);
                        }
                }
        }
@@ -558,21 +583,27 @@ void File<A>::dumpTableOfContents()
 // main function used by linker to instantiate archive files
 //
 ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts)
+                               const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
 {
        switch ( opts.objOpts.architecture ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( archive::Parser<x86_64>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( archive::Parser<x86>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
        }
        return NULL;
 }
index 31bab29c0107bad345f06d8e4c7c9f5f1d4c1592..1ed411ab9cf629e8046f0b730e1dab7f775eea84 100644 (file)
@@ -41,7 +41,7 @@ struct ParserOptions {
 };
 
 extern ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts);
+                                               const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts);
 
 } // namespace archive
 
index 3a11c18176dfb53d81abdb9d709b692da12826cb..0bc1831d981bae3cc336865f96c0dd766c6a1d08 100644 (file)
@@ -91,7 +91,7 @@ class File : public ld::relocatable::File
 {
 public:
                                                                                        File(const char* path, time_t mTime, const uint8_t* content, 
-                                                                                                       uint32_t contentLength, uint32_t ordinal, cpu_type_t arch);
+                                                                                                       uint32_t contentLength, cpu_type_t arch);
        virtual                                                                 ~File();
 
        // overrides of ld::File
@@ -101,7 +101,6 @@ public:
        virtual uint32_t                                                                        cpuSubType() const                      { return _cpuSubType; }
        
        // overrides of ld::relocatable::File 
-       virtual bool                                                                            objcReplacementClasses() const  { return false; }
        virtual DebugInfoKind                                                           debugInfo()     const                   { return _debugInfo; }
        virtual const char*                                                                     debugInfoPath() const           { return _debugInfoPath; }
        virtual time_t                                                                          debugInfoModificationTime() const 
@@ -199,11 +198,10 @@ public:
        static bool                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
        static const char*                              fileKind(const uint8_t* fileContent, uint64_t fileLength);
        static File*                                    parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-                                                                                       time_t modTime, uint32_t ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+                                                                                       time_t modTime, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
        static bool                                             libLTOisLoaded() { return (::lto_get_version() != NULL); }
        static bool                                             optimize(   const std::vector<const ld::Atom*>& allAtoms,
                                                                                                ld::Internal&                                           state,
-                                                                                               uint32_t                                                        nextInputOrdinal, 
                                                                                                const OptimizeOptions&                          options,
                                                                                                ld::File::AtomHandler&                          handler,
                                                                                                std::vector<const ld::Atom*>&           newAtoms, 
@@ -213,7 +211,7 @@ public:
 
 private:
        static const char*                              tripletPrefixForArch(cpu_type_t arch);
-       static ld::relocatable::File*   parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, const OptimizeOptions& options);
+       static ld::relocatable::File*   parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options);
 
        class CStringEquals
        {
@@ -246,17 +244,17 @@ std::vector<File*> Parser::_s_files;
 
 bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
 {
-       switch (architecture) {
-               case CPU_TYPE_I386:
-                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "i386-");
-               case CPU_TYPE_X86_64:
-                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "x86_64-");
-               case CPU_TYPE_ARM:
-                       for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                               if ( subarch == t->subType )
-                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix);
+       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+               if ( (architecture == t->cpuType) && (!(t->isSubType) || (subarch == t->cpuSubType)) ) {
+                       bool result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefix);
+                       if ( !result ) {
+                               // <rdar://problem/8434487> LTO only supports thumbv7 not armv7
+                               if ( t->llvmTriplePrefixAlt[0] != '\0' ) {
+                                       result = ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, t->llvmTriplePrefixAlt);
+                               }
                        }
-                       break;
+                       return result;
+               }
        }
        return false;
 }
@@ -264,18 +262,17 @@ bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type
 const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
 {
        if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
-               uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
-               switch (arch) {
-                       case CPU_TYPE_I386:
-                               return "i386";
-                       case CPU_TYPE_X86_64:
-                               return "x86_64";
-                       case CPU_TYPE_ARM:
-                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
+               cpu_type_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
+               for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                       if ( arch == t->cpuType ) {
+                                if ( t->isSubType ) {
                                        if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, t->llvmTriplePrefix) )
-                                               return t->subTypeName;
+                                               return t->archName;
+                               }
+                               else {
+                                       return t->archName;
                                }
-                               return "arm";
+                       }
                }
                return "unknown bitcode architecture";
        }
@@ -283,9 +280,9 @@ const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
 }
 
 File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                                                                                                       uint32_t ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles) 
+                                                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles) 
 {
-       File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
+       File* f = new File(path, modTime, fileContent, fileLength, architecture);
        _s_files.push_back(f);
        if ( logAllFiles ) 
                printf("%s\n", path);
@@ -293,7 +290,7 @@ File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char*
 }
 
 
-ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, const OptimizeOptions& options) 
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options) 
 {
        mach_o::relocatable::ParserOptions objOpts;
        objOpts.architecture            = options.arch;
@@ -312,7 +309,7 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint
                        modTime = statBuffer.st_mtime;
        }
        
-       ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, nextInputOrdinal, objOpts);
+       ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, ld::File::Ordinal::LTOOrdinal(), objOpts);
        if ( result != NULL )
                return result;
        throw "LLVM LTO, file is not of required architecture";
@@ -320,8 +317,8 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint
 
 
 
-File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ord, cpu_type_t arch) 
-       : ld::relocatable::File(pth,mTime,ord), _architecture(arch), _internalAtom(*this), 
+File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) 
+       : ld::relocatable::File(pth,mTime,ld::File::Ordinal::LTOOrdinal()), _architecture(arch), _internalAtom(*this), 
        _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth), 
        _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
        _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
@@ -399,7 +396,7 @@ File::File(const char* pth, time_t mTime, const uint8_t* content, uint32_t conte
                        uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
                        // make Atom using placement new operator
                        new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment, autohide);
-                       if ( scope == ld::Atom::scopeLinkageUnit )
+                       if ( scope != ld::Atom::scopeTranslationUnit )
                                _internalAtom.addReference(name);
                        if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name);
                }
@@ -458,7 +455,6 @@ void Atom::setCompiledAtom(const ld::Atom& atom)
 
 bool Parser::optimize(  const std::vector<const ld::Atom*>&    allAtoms,
                                                ld::Internal&                                           state,
-                                               uint32_t                                                        nextInputOrdinal, 
                                                const OptimizeOptions&                          options,
                                                ld::File::AtomHandler&                          handler,
                                                std::vector<const ld::Atom*>&           newAtoms, 
@@ -577,7 +573,7 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
                // 1 - atom scope is global (and not linkage unit).
                // 2 - included in nonLLVMRefs set.
                // If a symbol is not listed in exportList then LTO is free to optimize it away.
-               if ( (atom->scope() == ld::Atom::scopeGlobal) ) { 
+               if ( (atom->scope() == ld::Atom::scopeGlobal) && options.preserveAllGlobals ) { 
                        if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
                        ::lto_codegen_add_must_preserve_symbol(generator, name);
                }
@@ -680,7 +676,7 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
        }
        
        // parse generated mach-o file into a MachOReader
-       ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, options);
+       ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, options);
        
        // sync generated mach-o atoms with existing atoms ld knows about
        if ( logAtomsBeforeSync ) {
@@ -806,12 +802,20 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
 
 }
 
+class Mutex {
+       static pthread_mutex_t lto_lock;
+public:
+       Mutex() { pthread_mutex_lock(&lto_lock); }
+       ~Mutex() { pthread_mutex_unlock(&lto_lock); }
+};
+pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER;
 
 //
 // Used by archive reader to see if member is an llvm bitcode file
 //
 bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch)
 {
+       Mutex lock;
        return Parser::validFile(fileContent, fileLength, architecture, subarch);
 }
 
@@ -820,11 +824,12 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t ar
 // main function used by linker to instantiate ld::Files
 //
 ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                               const char* path, time_t modTime, uint32_t ordinal, 
+                                                               const char* path, time_t modTime, 
                                                                cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
 {
+       Mutex lock;
        if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
-               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
+               return Parser::parse(fileContent, fileLength, path, modTime, architecture, subarch, logAllFiles);
        else
                return NULL;
 }
@@ -834,6 +839,7 @@ ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
 //
 const char* version()
 {
+       Mutex lock;
        return ::lto_get_version();
 }
 
@@ -843,6 +849,7 @@ const char* version()
 //
 bool libLTOisLoaded()
 {
+       Mutex lock;
        return (::lto_get_version() != NULL);
 }
 
@@ -851,6 +858,7 @@ bool libLTOisLoaded()
 //
 const char* archName(const uint8_t* fileContent, uint64_t fileLength)
 {
+       Mutex lock;
        return Parser::fileKind(fileContent, fileLength);
 }
 
@@ -859,13 +867,13 @@ const char* archName(const uint8_t* fileContent, uint64_t fileLength)
 //
 bool optimize(  const std::vector<const ld::Atom*>&    allAtoms,
                                ld::Internal&                                           state,
-                               uint32_t                                                        nextInputOrdinal, 
                                const OptimizeOptions&                          options,
                                ld::File::AtomHandler&                          handler,
                                std::vector<const ld::Atom*>&           newAtoms, 
                                std::vector<const char*>&                       additionalUndefines)
 { 
-       return Parser::optimize(allAtoms, state, nextInputOrdinal, options, handler, newAtoms, additionalUndefines);
+       Mutex lock;
+       return Parser::optimize(allAtoms, state, options, handler, newAtoms, additionalUndefines);
 }
 
 
index dbb82a5aa609bd6a2967137f4f35819b22b42b4b..492d32ccd96aff35bdd04241c95d4dbde4fc2903 100644 (file)
@@ -38,13 +38,13 @@ extern const char* archName(const uint8_t* fileContent, uint64_t fileLength);
 extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
 
 extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                                       const char* path, time_t modTime, uint32_t ordinal, 
+                                                                       const char* path, time_t modTime, 
                                                                        cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
 
 struct OptimizeOptions {
        const char*                                                     outputFilePath;
        const char*                                                     tmpObjectFilePath;
-       bool                                                            allGlobalsAReDeadStripRoots;
+       bool                                                            preserveAllGlobals;
        bool                                                            verbose; 
        bool                                                            saveTemps; 
        bool                                                            pie; 
@@ -59,7 +59,6 @@ struct OptimizeOptions {
 
 extern bool    optimize(   const std::vector<const ld::Atom*>& allAtoms,
                                                ld::Internal&                                           state,
-                                               uint32_t                                                        nextInputOrdinal, 
                                                const OptimizeOptions&                          options,
                                                ld::File::AtomHandler&                          handler,
                                                std::vector<const ld::Atom*>&           newAtoms, 
index 39cebfb92260c4c07ff197efd8df04e933a84f42..11c03ac28013909191d4ebe0ad9eb7ddc9a1f883 100644 (file)
@@ -40,7 +40,7 @@
 #include "MachOFileAbstraction.hpp"
 #include "MachOTrie.hpp"
 #include "macho_dylib_file.h"
-
+#include "../code-sign-blobs/superblob.h"
 
 namespace mach_o {
 namespace dylib {
@@ -144,7 +144,7 @@ class File : public ld::dylib::File
 public:
        static bool                                                             validFile(const uint8_t* fileContent, bool executableOrDylib);
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
-                                                                                                       time_t mTime, uint32_t ordinal, bool linkingFlatNamespace, 
+                                                                                                       time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
                                                                                                        ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers, 
                                                                                                        bool logAllFiles, const char* installPath, bool indirectDylib);
@@ -165,6 +165,7 @@ public:
        virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
        virtual bool                                                    hasWeakDefinition(const char* name) const;
        virtual bool                                                    allSymbolsAreWeakImported() const;
+       virtual const void*                                             codeSignatureDR() const         { return _codeSignatureDR; }
 
 
 protected:
@@ -218,6 +219,7 @@ private:
        NameSet                                                                         _ignoreExports;
        const char*                                                                     _parentUmbrella;
        ImportAtom<A>*                                                          _importAtom;
+       const void*                                                                     _codeSignatureDR;
        bool                                                                            _noRexports;
        bool                                                                            _hasWeakExports;
        bool                                                                            _deadStrippable;
@@ -240,7 +242,7 @@ template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imagei
 template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
 
 template <typename A>
-File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, uint32_t ord,
+File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
                                ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers,
                                bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
@@ -250,7 +252,8 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        _objcContraint(ld::File::objcConstraintNone),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
        _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
-       _parentUmbrella(NULL), _importAtom(NULL), _noRexports(false), _hasWeakExports(false), 
+       _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), 
+       _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
         _providedAtom(false), _explictReExportFound(false)
 {
@@ -281,6 +284,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
        const macho_dysymtab_command<P>* dynamicInfo = NULL;
        const macho_dyld_info_command<P>* dyldInfo = NULL;
+       const macho_linkedit_data_command<P>* codeSignature = NULL;
        const macho_nlist<P>* symbolTable = NULL;
        const char*     strings = NULL;
        bool compressedLinkEdit = false;
@@ -294,6 +298,8 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                symtab = (macho_symtab_command<P>*)cmd;
                                symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
                                strings = (char*)header + symtab->stroff();
+                               if ( (symtab->stroff() + symtab->strsize()) > fileLength )
+                                       throwf("mach-o string pool extends beyond end of file in %s", pth);
                                break;
                        case LC_DYSYMTAB:
                                dynamicInfo = (macho_dysymtab_command<P>*)cmd;
@@ -333,6 +339,9 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) )
                                        warning("building for MacOSX, but linking against dylib built for iOS: %s", pth);
                                break;
+                       case LC_CODE_SIGNATURE:
+                               codeSignature = (macho_linkedit_data_command<P>* )cmd;
+                               break;
                        case macho_segment_command<P>::CMD:
                                // check for Objective-C info
                                if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
@@ -460,6 +469,25 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                _importAtom = new ImportAtom<A>(*this, importNames);
        }
        
+       // if the dylib is code signed, look for its Designated Requirement
+       if ( codeSignature != NULL ) {
+               const Security::BlobCore* overallSignature = (Security::BlobCore*)((char*)header + codeSignature->dataoff());
+               typedef Security::SuperBlob<Security::kSecCodeMagicEmbeddedSignature> EmbeddedSignatureBlob;
+               typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsBlob;
+               const EmbeddedSignatureBlob* signature = EmbeddedSignatureBlob::specific(overallSignature);
+               if ( signature->validateBlob(codeSignature->datasize()) ) {
+                       const InternalRequirementsBlob* ireq = signature->find<InternalRequirementsBlob>(Security::cdRequirementsSlot);
+                       if ( (ireq != NULL) && ireq->validateBlob() ) {
+                               const Security::BlobCore* dr = ireq->find(Security::kSecDesignatedRequirementType);
+                               if ( (dr != NULL) && dr->validateBlob(Security::kSecCodeMagicRequirement) ) {
+                                       // <rdar://problem/10968461> make copy because mapped file is about to be unmapped
+                                       _codeSignatureDR = ::malloc(dr->length());
+                                       ::memcpy((void*)_codeSignatureDR, dr, dr->length());
+                               }
+                       }
+               }
+       }
+       
        // build hash table
        if ( dyldInfo != NULL ) 
                buildExportHashTableFromExportInfo(dyldInfo, fileContent);
@@ -577,6 +605,10 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
                                                this->addSymbol(symName, weakDef, false, 0);
                                                return;
                                        }
+                                       else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
+                                               _dylibInstallPath = symName;
+                                               return;
+                                       }
                                        else {
                                                warning("bad symbol action: %s in dylib %s", name, this->path());
                                        }
@@ -838,8 +870,8 @@ public:
        static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
        static ld::dylib::File*                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
-                                                                                                                       uint32_t ordinal, const Options& opts, bool indirectDylib) {
-                                                                                                                        return new File<A>(fileContent, fileLength, path, mTime,
+                                                                                                                       ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
+                                                                                                                       return new File<A>(fileContent, fileLength, path, mTime,
                                                                                                                                                        ordinal, opts.flatNamespace(), 
                                                                                                                                                        opts.linkingMainExecutable(),
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
@@ -942,22 +974,28 @@ bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDylibor
 // main function used by linker to instantiate ld::Files
 //
 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                       const char* path, time_t modTime, const Options& opts, uint32_t ordinal, 
+                                                       const char* path, time_t modTime, const Options& opts, ld::File::Ordinal ordinal, 
                                                        bool bundleLoader, bool indirectDylib)
 {
        switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
                                return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( Parser<x86>::validFile(fileContent, bundleLoader) )
                                return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( Parser<arm>::validFile(fileContent, bundleLoader) )
                                return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
+#endif
        }
        return NULL;
 }
index d26f50e3d514eec1c00040b01b2160c2717faaaf..ad03af1af1c9e0f5811037018f0f7331bfd55f82 100644 (file)
@@ -32,7 +32,7 @@ namespace mach_o {
 namespace dylib {
 
 extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-                                                               time_t modTime, const Options& opts, uint32_t ordinal, 
+                                                               time_t modTime, const Options& opts, ld::File::Ordinal ordinal, 
                                                                bool bundleLoader, bool indirectDylib);
 
 } // namespace dylib
index e79d2618c01215181f594fdcc15b39e98bc499d9..50f53273d2e79829b94aad9e2bf6b9003e85d257 100644 (file)
@@ -70,7 +70,7 @@ template <typename A>
 class File : public ld::relocatable::File
 {
 public:
-                                                                                       File(const char* p, time_t mTime, const uint8_t* content, uint32_t ord) :
+                                                                                       File(const char* p, time_t mTime, const uint8_t* content, ld::File::Ordinal ord) :
                                                                                                ld::relocatable::File(p,mTime,ord), _fileContent(content),
                                                                                                _sectionsArray(NULL), _atomsArray(NULL),
                                                                                                _sectionsArrayCount(0), _atomsArrayCount(0),
@@ -80,7 +80,7 @@ public:
                                                                                                _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), 
                                                                                                _objConstraint(ld::File::objcConstraintNone),
                                                                                                _cpuSubType(0),
-                                                                                               _ojcReplacmentClass(false),  _canScatterAtoms(false) {}
+                                                                                               _canScatterAtoms(false) {}
        virtual                                                                 ~File();
 
        // overrides of ld::File
@@ -89,7 +89,6 @@ public:
                                                                                                                                                                        { return false; }
        
        // overrides of ld::relocatable::File 
-       virtual bool                                                                            objcReplacementClasses() const  { return _ojcReplacmentClass; }
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
        virtual DebugInfoKind                                                           debugInfo() const                               { return _debugInfoKind; }
@@ -124,7 +123,6 @@ private:
        const macho_section<P>*                                 _dwarfDebugStringSect;
        ld::File::ObjcConstraint                                _objConstraint;
        uint32_t                                                                _cpuSubType;
-       bool                                                                    _ojcReplacmentClass;
        bool                                                                    _canScatterAtoms;
 };
 
@@ -861,8 +859,9 @@ public:
                                                                                                                                cpu_subtype_t subtype=0);
        static const char*                                                              fileKind(const uint8_t* fileContent);
        static bool                                                                             hasObjC2Categories(const uint8_t* fileContent);
+       static bool                                                                             hasObjC1Categories(const uint8_t* fileContent);
        static ld::relocatable::File*                                   parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                                                                                       const char* path, time_t modTime, uint32_t ordinal,
+                                                                                                                       const char* path, time_t modTime, ld::File::Ordinal ordinal,
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
                                                                                                                                                ordinal, opts.convertUnwindInfo);
@@ -972,6 +971,7 @@ public:
        void                                                                                    addDtraceExtraInfos(const SourceLocation& src, const char* provider);
        const char*                                                                             scanSymbolTableForAddress(uint64_t addr);
        bool                                                                                    convertUnwindInfo() { return _convertUnwindInfo; }
+       bool                                                                                    hasDataInCodeLabels() { return _hasDataInCodeLabels; }
 
        
        void                                                    addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target);
@@ -1048,7 +1048,7 @@ private:
 
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, 
-                                                                                                                       uint32_t ordinal, bool convertUnwindInfo);
+                                                                                                                       ld::File::Ordinal ordinal, bool convertUnwindInfo);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        uint8_t                                                                                 loadCommandSizeMask();
        bool                                                                                    parseLoadCommands();
@@ -1075,7 +1075,7 @@ private:
        uint32_t                                                                        _fileLength;
        const char*                                                                     _path;
        time_t                                                                          _modTime;
-       uint32_t                                                                        _ordinal;
+       ld::File::Ordinal                                                       _ordinal;
        
        // filled in by parseLoadCommands()
        File<A>*                                                                        _file;
@@ -1102,6 +1102,7 @@ private:
        bool                                                                            _AppleObjc; // FSF has objc that uses different data layout
        bool                                                                            _overlappingSymbols;
        bool                                                                            _convertUnwindInfo;
+       bool                                                                            _hasDataInCodeLabels;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
@@ -1112,7 +1113,7 @@ private:
 
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                                       uint32_t ordinal, bool convertDUI)
+                                       ld::File::Ordinal ordinal, bool convertDUI)
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
@@ -1122,7 +1123,7 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                        _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
                        _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
                        _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
-                       _overlappingSymbols(false), _convertUnwindInfo(convertDUI), 
+                       _overlappingSymbols(false), _convertUnwindInfo(convertDUI), _hasDataInCodeLabels(false), 
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
@@ -1207,9 +1208,9 @@ const char* Parser<arm>::fileKind(const uint8_t* fileContent)
                return NULL;
        if ( header->cputype() != CPU_TYPE_ARM )
                return NULL;
-       for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-               if ( t->subType == (cpu_subtype_t)header->cpusubtype() ) {
-                       return t->subTypeName;
+       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+               if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
+                       return t->archName;
                }
        }
        return "arm???";
@@ -1244,6 +1245,35 @@ bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
        return false;
 }
 
+
+template <typename A>
+bool Parser<A>::hasObjC1Categories(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       const uint32_t cmd_count = header->ncmds();
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+       const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
+                       const macho_section<P>* sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+                       for (uint32_t si=0; si < segment->nsects(); ++si) {
+                               const macho_section<P>* sect = &sectionsStart[si];
+                               if ( (sect->size() > 0) 
+                                       && (strcmp(sect->sectname(), "__category") == 0)
+                                       && (strcmp(sect->segname(), "__OBJC") == 0) ) {
+                                               return true;
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               if ( cmd > cmdsEnd )
+                       throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+       }
+       return false;
+}
+
 template <typename A>
 int Parser<A>::pointerSorter(const void* l, const void* r)
 {
@@ -1724,6 +1754,7 @@ void Parser<A>::prescanSymbolTable()
        _tentativeDefinitionCount = 0;
        _absoluteSymbolCount = 0;
        _symbolsInSections = 0;
+       _hasDataInCodeLabels = false;
        for (uint32_t i=0; i < this->_symbolCount; ++i) {
                const macho_nlist<P>& sym =     symbolFromIndex(i);
                // ignore stabs
@@ -1769,9 +1800,12 @@ void Parser<A>::prescanSymbolTable()
                        continue;
                
                // 'L' labels do not denote atom breaks
-               if ( symbolName[0] == 'L' )
+               if ( symbolName[0] == 'L' ) {
+                       // <rdar://problem/9218847> Formalize data in code with L$start$ labels
+                       if ( strncmp(symbolName, "L$start$", 8) == 0 ) 
+                               _hasDataInCodeLabels = true;
                        continue;
-               
+               }
                // how many def syms in each section
                if ( sym.n_sect() > _machOSectionsCount )
                        throw "bad n_sect in symbol table";
@@ -1986,8 +2020,6 @@ void Parser<A>::makeSections()
                                        _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
                                else
                                        _file->_objConstraint = ld::File::objcConstraintRetainRelease;
-                               if ( (flags & 1) == 1 )
-                                       _file->_ojcReplacmentClass = true;
                                if ( sect->size() > 8 ) {
                                        warning("section %s/%s has unexpectedly large size %llu in %s", 
                                                        sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
@@ -5532,6 +5564,7 @@ bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocati
        
 
 
+#if SUPPORT_ARCH_arm_any
 template <>
 bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocation_info<P>* reloc)
 {
@@ -5984,6 +6017,7 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
        }
        return result;
 }
+#endif
 
 
 
@@ -6116,6 +6150,46 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
                }
        }
        
+       // <rdar://problem/9218847> track data-in-code
+       if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) {
+               for (uint32_t i=0; i < parser.symbolCount(); ++i) {
+                       const macho_nlist<P>& sym =     parser.symbolFromIndex(i);
+                       // ignore stabs
+                       if ( (sym.n_type() & N_STAB) != 0 )
+                               continue;
+                       // ignore non-definitions
+                       if ( (sym.n_type() & N_TYPE) != N_SECT )
+                               continue;
+
+                       // 'L' labels do not denote atom breaks
+                       const char* symbolName = parser.nameFromSymbol(sym);
+                       if ( symbolName[0] == 'L' ) {
+                               if ( strncmp(symbolName, "L$start$", 8) == 0 ) {
+                                       ld::Fixup::Kind kind = ld::Fixup::kindNone;
+                                       if ( strncmp(&symbolName[8], "data$", 5) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeStartData;
+                                       else if ( strncmp(&symbolName[8], "code$", 5) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeEnd;
+                                       else if ( strncmp(&symbolName[8], "jt8$", 4) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeStartJT8;
+                                       else if ( strncmp(&symbolName[8], "jt16$", 4) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeStartJT16;
+                                       else if ( strncmp(&symbolName[8], "jt32$", 4) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeStartJT32;
+                                       else if ( strncmp(&symbolName[8], "jta32$", 4) == 0 )
+                                               kind = ld::Fixup::kindDataInCodeStartJTA32;
+                                       else 
+                                               warning("unknown L$start$ label %s in file %s", symbolName, this->file().path());
+                                       if ( kind != ld::Fixup::kindNone ) {
+                                               Atom<A>* inAtom = parser.findAtomByAddress(sym.n_value());
+                                               typename Parser<A>::SourceLocation src(inAtom, sym.n_value() - inAtom->objectAddress());
+                                               parser.addFixup(src, ld::Fixup::k1of1, kind);
+                                       }
+                               }
+                       }
+               }
+       }
+       
        // add follow-on fixups for aliases
        if ( _hasAliases ) {
                for(Atom<A>* p = _beginAtoms; p < _endAtoms; ++p) {
@@ -6136,21 +6210,27 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
 // main function used by linker to instantiate ld::Files
 //
 ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts)
+                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts)
 {
        switch ( opts.architecture ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) )
                                return mach_o::relocatable::Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) )
                                return mach_o::relocatable::Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
                                return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
        }
        return NULL;
 }
@@ -6229,6 +6309,17 @@ bool hasObjC2Categories(const uint8_t* fileContent)
        return false;
 }                              
 
+//
+// Used by archive reader when -ObjC option is specified
+//     
+bool hasObjC1Categories(const uint8_t* fileContent)
+{
+       if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<x86>::hasObjC1Categories(fileContent);
+       }
+       return false;
+}
+
 
 
 } // namespace relocatable
index 6d0e25e0fc12b8ae5f943227474b2f5615c78834..021c3f2ff6f77340d4e2db133ce5a6e6cf64444e 100644 (file)
@@ -40,7 +40,7 @@ struct ParserOptions {
 };
 
 extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
-                                                                       const char* path, time_t modTime, uint32_t ordinal, 
+                                                                       const char* path, time_t modTime, ld::File::Ordinal ordinal, 
                                                                        const ParserOptions& opts);
                                                                        
 extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts);
@@ -49,6 +49,8 @@ extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_sub
 
 extern bool hasObjC2Categories(const uint8_t* fileContent);                                    
 
+extern bool hasObjC1Categories(const uint8_t* fileContent);
+
 extern const char* archName(const uint8_t* fileContent);                                       
 
 } // namespace relocatable
index 660f66db423221fa4a4a72051e38ba9e4c45656f..4098958ec7c416339adadaab2e60b8e8756929d1 100644 (file)
@@ -61,9 +61,9 @@ class File : public ld::File
 {
 public:
                                                                File(const char* segmentName, const char* sectionName, const char* pth, 
-                                                                       const uint8_t fileContent[], uint64_t fileLength, uint32_t ord, 
+                                                                       const uint8_t fileContent[], uint64_t fileLength, 
                                                                        const char* symbolName="sect_create")
-                                                                       : ld::File(pth, 0, ord),
+                                                                       : ld::File(pth, 0, ld::File::Ordinal::NullOrdinal(), Other),
                                                                          _atom(*this, symbolName, fileContent, fileLength), 
                                                                          _section(segmentName, sectionName, ld::Section::typeUnclassified) { }
        virtual                                         ~File() { }
@@ -90,10 +90,10 @@ Atom::Atom(File& f, const char* n,  const uint8_t* content, uint64_t sz)
 // main function used by linker for -sectcreate
 //
 ld::File* parse(const char* segmentName, const char* sectionName, const char* path, 
-                                                                       const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal
+                               const uint8_t fileContent[], uint64_t fileLength
                                                                        const char* symbolName)
 {
-       return new File(segmentName, sectionName, path, fileContent, fileLength, ordinal, symbolName);
+       return new File(segmentName, sectionName, path, fileContent, fileLength, symbolName);
 }
 
 
index 04db805a417438aa8c13ffbe21899f77b038b11a..e105a07d73bfe3dbd02ddebc9468776e51652e56 100644 (file)
@@ -32,7 +32,7 @@
 namespace opaque_section {
 
 extern ld::File* parse(const char* segmentName, const char* sectionName, const char* path, 
-                                                                       const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, 
+                                                                       const uint8_t fileContent[], uint64_t fileLength, 
                                                                        const char* symbolName="opaque_section");
 
 
index 773031e6f843128a1bd9aea694c23eeb2c777e21..06953a709e9c1ede1a3cb232be3237f17ab6064c 100644 (file)
@@ -412,9 +412,45 @@ void doPass(const Options& opts, ld::Internal& state)
                return;
        if (_s_log) fprintf(stderr, "ld:  __text section size=%llu, might need branch islands\n", totalTextSize);
        
-       // figure out how many regions of branch islands will be needed
-       const uint32_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
-       const int kIslandRegionsCount = totalTextSize / kBetweenRegions;
+       // Figure out how many regions of branch islands will be needed, and their locations.
+       // Construct a vector containing the atoms after which branch islands will be inserted,
+       // taking into account follow on fixups. No atom run without an island can exceed kBetweenRegions.
+       const uint64_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
+       std::vector<const ld::Atom*> branchIslandInsertionPoints; // atoms in the atom list after which branch islands will be inserted
+       uint64_t previousIslandEndAddr = 0;
+       const ld::Atom *insertionPoint;
+       branchIslandInsertionPoints.reserve(totalTextSize/kBetweenRegions*2);
+       for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
+               const ld::Atom* atom = *it;
+               // if we move past the next atom, will the run length exceed kBetweenRegions?
+               if ( atom->sectionOffset() + atom->size() - previousIslandEndAddr > kBetweenRegions ) {
+                       // yes. Add the last known good location (atom) for inserting a branch island.
+                       if ( insertionPoint == NULL )
+                               throwf("Unable to insert branch island. No insertion point available.");
+                       branchIslandInsertionPoints.push_back(insertionPoint);
+                       previousIslandEndAddr = insertionPoint->sectionOffset()+insertionPoint->size();
+                       insertionPoint = NULL;
+               }
+               // Can we insert an island after this atom? If so then keep track of it.
+               if ( !atom->hasFixupsOfKind(ld::Fixup::kindNoneFollowOn) )
+                       insertionPoint = atom;
+       }
+       // add one more island after the last atom
+       if (insertionPoint != NULL)
+               branchIslandInsertionPoints.push_back(insertionPoint);
+       const int kIslandRegionsCount = branchIslandInsertionPoints.size();
+       if (_s_log) {
+               fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
+               for (std::vector<const ld::Atom*>::iterator it = branchIslandInsertionPoints.begin(); it != branchIslandInsertionPoints.end(); ++it) {
+                       const ld::Atom* atom = *it;
+                       const ld::File *file = atom->file();
+                       fprintf(stderr, "ld: branch island will be inserted at 0x%llx after %s", atom->sectionOffset()+atom->size(), atom->name());
+                       if (file) fprintf(stderr, " (%s)", atom->file()->path());
+                       fprintf(stderr, "\n");
+               }
+       }
+
+
        typedef std::map<TargetAndOffset,const ld::Atom*, TargetAndOffsetComparor> AtomToIsland;
     AtomToIsland* regionsMap[kIslandRegionsCount];
        std::vector<const ld::Atom*>* regionsIslands[kIslandRegionsCount];
@@ -423,7 +459,6 @@ void doPass(const Options& opts, ld::Internal& state)
                regionsIslands[i] = new std::vector<const ld::Atom*>();
        }
        unsigned int islandCount = 0;
-       if (_s_log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
        
        // create islands for branches in __text that are out of range
        for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ++ait) {
@@ -533,30 +568,25 @@ void doPass(const Options& opts, ld::Internal& state)
                if ( _s_log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
                std::vector<const ld::Atom*> newAtomList;
                newAtomList.reserve(textSection->atoms.size()+islandCount);
-               uint64_t islandRegionAddr = kBetweenRegions;;
-               int regionIndex = 0;
-               for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
-                       const ld::Atom* atom = *it;
-                       if ( (atom->sectionOffset()+atom->size()) > islandRegionAddr ) {
-                               std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
-                               for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
-                                       const ld::Atom* islandAtom = *rit;
-                                       newAtomList.push_back(islandAtom);
-                                       if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
-                               }
-                               ++regionIndex;
-                               islandRegionAddr += kBetweenRegions;
+               
+               uint64_t regionIndex = 0;
+               for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ait++) {
+                       newAtomList.push_back(*ait);
+                       // copy over atoms until we find an island insertion point
+                       // Note that the last insertion point is the last atom, so this loop never moves the iterator to atoms.end().
+                       while (*ait != branchIslandInsertionPoints[regionIndex]) {
+                               ait++;
+                               newAtomList.push_back(*ait);
                        }
-                       newAtomList.push_back(atom);
-               }
-               // put any remaining islands at end of __text section
-               if ( regionIndex < kIslandRegionsCount ) {
+                       
+                       // insert the branch island atoms after the insertion point atom
                        std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
                        for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
                                const ld::Atom* islandAtom = *rit;
                                newAtomList.push_back(islandAtom);
                                if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
                        }
+                       regionIndex++;
                }
                // swap in new list of atoms for __text section
                textSection->atoms.clear();
index 7a2bd50ea6b2907cf4f7ab59643da7a943e4332e..443f28e3c4494bd2c0aac475a2373d3f66d54c06 100644 (file)
@@ -328,7 +328,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                                if ( pos == thumbToAtomMap.end() ) {
                                                                        if ( opts.archSupportsThumb2() ) {
                                                                                // <rdar://problem/9116044> make long-branch style shims for arm kexts
-                                                                               if ( makingKextBundle )
+                                                                               if ( makingKextBundle && opts.allowTextRelocs() )
                                                                                        shim = new NoPICThumb2ToArmShimAtom(target, *sect);
                                                                                else
                                                                                        shim = new Thumb2ToArmShimAtom(target, *sect);
@@ -365,7 +365,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                                std::map<const Atom*, const Atom*>::iterator pos = atomToThumbMap.find(target);
                                                                if ( pos == atomToThumbMap.end() ) {
                                                                        // <rdar://problem/9116044> make long-branch style shims for arm kexts
-                                                                       if ( makingKextBundle )
+                                                                       if ( makingKextBundle && opts.allowTextRelocs() )
                                                                                shim = new NoPICARMtoThumbShimAtom(target, *sect);
                                                                        else
                                                                                shim = new ARMtoThumbShimAtom(target, *sect);
index 86c8eec9789d143e8eb0fd2374a604e146adbe0d..858b40f7ef43ad419389685dbebd9c9d6d711965 100644 (file)
@@ -774,12 +774,16 @@ static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::In
 
        // create atom that contains the whole compact unwind table
        switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
                        break;
+#endif
                default:
                        assert(0 && "no compact unwind for arch");
        }       
@@ -876,12 +880,16 @@ static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, cons
                                                                                        uint32_t startOffset, uint32_t endOffset, uint32_t cui)
 {
        switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        state.addAtom(*new CompactUnwindAtom<x86_64>(state, atom, startOffset, endOffset-startOffset, cui));
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
                        break;
+#endif
        }
 }
 
index 665e3ae3861072c1151bfd946ff6303855cb292f..02055f34242a134b36eae90af6ed31b8009e125f 100644 (file)
@@ -77,9 +77,9 @@ class File : public ld::File
 {
 public:
                                                                File(const char* segmentName, const char* sectionName, const char* pth, 
-                                                                       const uint8_t fileContent[], uint64_t fileLength, uint32_t ord, 
+                                                                       const uint8_t fileContent[], uint64_t fileLength, Ordinal ord, 
                                                                        const char* symbolName="dof")
-                                                                       : ld::File(pth, 0, ord),
+                                                                       : ld::File(pth, 0, ord, Other),
                                                                          _atom(*this, symbolName, fileContent, fileLength), 
                                                                          _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
        virtual                                         ~File() {}
@@ -299,7 +299,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                        sectionNamesUsed.insert(sectionName);
                        char symbolName[strlen(providerName)+64];
                        sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
-                       File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, 0, symbolName);
+                       File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, ld::File::Ordinal::NullOrdinal(), symbolName);
                        if ( log ) {
                                fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
                        }
index b209b1dd61217066c1c92958fce8991a97cb866b..cf6f1d4095bfb140e1d41acb1689bececef1ea16 100644 (file)
@@ -50,7 +50,6 @@ struct objc_image_info  {
        uint32_t        flags;
 };
 
-#define OBJC_IMAGE_IS_REPLACEMENT              (1<<0)
 #define OBJC_IMAGE_SUPPORTS_GC                 (1<<1)
 #define OBJC_IMAGE_REQUIRES_GC                 (1<<2)
 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD   (1<<3)
@@ -65,7 +64,7 @@ template <typename A>
 class ObjCImageInfoAtom : public ld::Atom {
 public:
                                                                                        ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, 
-                                                                                                                       bool compaction, bool objcReplacementClasses, bool abi2);
+                                                                                                                       bool compaction, bool abi2);
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
@@ -91,15 +90,13 @@ template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA",
 
 template <typename A>
 ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction, 
-                                                                               bool objcReplacementClasses, bool abi2)
+                                                                               bool abi2)
        : ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2))
 {  
        
        uint32_t value = 0;
-       if ( objcReplacementClasses ) 
-               value = OBJC_IMAGE_IS_REPLACEMENT;
        switch ( objcConstraint ) {
                case ld::File::objcConstraintNone:
                case ld::File::objcConstraintRetainRelease:
@@ -143,7 +140,7 @@ public:
        virtual void                                                    setScope(Scope)                                 { }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const {
                bzero(buffer, size());
-               A::P::E::set32(*((uint32_t*)(&buffer[0])), 24);
+               A::P::E::set32(*((uint32_t*)(&buffer[0])), 3*sizeof(pint_t)); // entry size
                A::P::E::set32(*((uint32_t*)(&buffer[4])), _methodCount);
        }
        virtual ld::Fixup::iterator                             fixupsBegin() const     { return (ld::Fixup*)&_fixups[0]; }
@@ -775,6 +772,35 @@ private:
        const std::set<const ld::Atom*>& _dead;
 };
 
+       struct AtomSorter
+       {       
+               bool operator()(const Atom* left, const Atom* right)
+               {
+                       // sort by file ordinal, then object address, then zero size, then symbol name
+                       // only file based atoms are supported (file() != NULL)
+                       if (left==right) return false;
+                       const File *leftf = left->file();
+                       const File *rightf = right->file();
+                       
+                       if (leftf == rightf) {
+                               if (left->objectAddress() != right->objectAddress()) {
+                                       return left->objectAddress() < right->objectAddress();
+                               } else {
+                                       // for atoms in the same file with the same address, zero sized
+                                       // atoms must sort before nonzero sized atoms
+                                       if ((left->size() == 0 && right->size() > 0) || (left->size() > 0 && right->size() == 0))
+                                               return left->size() < right->size();
+                                       return strcmp(left->name(), right->name());
+                               }
+                       }
+                       return  (leftf->ordinal() < rightf->ordinal());
+               }
+       };
+       
+       static void sortAtomVector(std::vector<const Atom*> &atoms) {
+               std::sort(atoms.begin(), atoms.end(), AtomSorter());
+       }
+
 template <typename A>
 void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
 {
@@ -798,6 +824,7 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
        // build map of all classes in this image that have categories on them
        typedef std::map<const ld::Atom*, std::vector<const ld::Atom*>*> CatMap;
        CatMap classToCategories;
+       std::vector<const ld::Atom*> classOrder;
        std::set<const ld::Atom*> deadAtoms;
        ld::Internal::FinalSection* methodListSection = NULL;
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
@@ -813,7 +840,7 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                        continue;
                                }
                                assert(categoryAtom != NULL);
-                               assert(categoryAtom->size() == Category<A>::size());
+                               assert(categoryAtom->size() >= Category<A>::size());
                                // ignore categories also in __objc_nlcatlist
                                if ( nlcatListAtoms.count(categoryAtom) != 0 )
                                        continue;
@@ -824,6 +851,7 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                        CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
                                        if ( pos == classToCategories.end() ) {
                                                classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
+                                               classOrder.push_back(categoryOnClassAtom);
                                        }
                                        classToCategories[categoryOnClassAtom]->push_back(categoryAtom);
                                        // mark category atom and catlist atom as dead
@@ -840,10 +868,11 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
        // if found some categories
        if ( classToCategories.size() != 0 ) {
                assert(methodListSection != NULL);
+               sortAtomVector(classOrder);
                // alter each class definition to have new method list which includes all category methods
-               for (CatMap::iterator it=classToCategories.begin(); it != classToCategories.end(); ++it) {
-                       const ld::Atom* classAtom = it->first;
-                       const std::vector<const ld::Atom*>* categories = it->second;
+               for (std::vector<const ld::Atom*>::iterator it = classOrder.begin(); it != classOrder.end(); it++) {
+                       const ld::Atom* classAtom = *it;
+                       const std::vector<const ld::Atom*>* categories = classToCategories[classAtom];
                        assert(categories->size() != 0);
                        // if any category adds instance methods, generate new merged method list, and replace
                        if ( OptimizeCategories<A>::hasInstanceMethods(state, categories) ) { 
@@ -1145,17 +1174,21 @@ void doPass(const Options& opts, ld::Internal& state)
                
                // add image info atom
                switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                        case CPU_TYPE_X86_64:
                                state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction, 
-                                                               state.hasObjcReplacementClasses, true));
+                                                               true));
                                break;
+#endif
+#if SUPPORT_ARCH_i386
                        case CPU_TYPE_I386:
                                state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction, 
-                                                       state.hasObjcReplacementClasses, opts.objCABIVersion2POverride() ? true : false));
+                                                       opts.objCABIVersion2POverride() ? true : false));
                                break;
+#endif
                        case CPU_TYPE_ARM:
                                state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction, 
-                                                       state.hasObjcReplacementClasses, true));
+                                                       true));
                                break;
                        default:
                                assert(0 && "unknown objc arch");
@@ -1165,18 +1198,24 @@ void doPass(const Options& opts, ld::Internal& state)
        if ( opts.objcCategoryMerging() ) {
                // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
                switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                        case CPU_TYPE_X86_64:
                                OptimizeCategories<x86_64>::doit(opts, state);
                                break;
+#endif
+#if SUPPORT_ARCH_i386
                        case CPU_TYPE_I386:
                                // disable optimization until fully tested
-                               //if ( opts.objCABIVersion2POverride() )
-                               //      OptimizeCategories<x86>::doit(opts, state);
+                               if ( opts.objCABIVersion2POverride() )
+                    OptimizeCategories<x86>::doit(opts, state);
                                break;
+#endif
+#if SUPPORT_ARCH_arm_any
                        case CPU_TYPE_ARM:
                                // disable optimization until fully tested
-                               //OptimizeCategories<arm>::doit(opts, state);
+                               OptimizeCategories<arm>::doit(opts, state);
                                break;
+#endif
                        default:
                                assert(0 && "unknown objc arch");
                }       
index ce17a35c0fe8786957e8debf58008af6e68784b4..6876d8f6659f397727673ee3d68fd6acf436b6bd 100644 (file)
@@ -193,8 +193,9 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
        // sort by .o order
        const ld::File* leftFile = left->file();
        const ld::File* rightFile = right->file();
-       uint32_t leftFileOrdinal = (leftFile != NULL) ? leftFile->ordinal() : 0;
-       uint32_t rightFileOrdinal = (rightFile != NULL) ? rightFile->ordinal() : 0;
+       // <rdar://problem/10830126> properly sort if on file is NULL and the other is not
+       ld::File::Ordinal leftFileOrdinal = (leftFile != NULL) ? leftFile->ordinal() : ld::File::Ordinal::NullOrdinal();
+       ld::File::Ordinal rightFileOrdinal = (rightFile != NULL) ? rightFile->ordinal() : ld::File::Ordinal::NullOrdinal();
        if ( leftFileOrdinal != rightFileOrdinal )
                return leftFileOrdinal< rightFileOrdinal;
 
index e8deddaa2508c3c3ad6d3170878dfd87b64fd1d8..4650ddbbb134ad2f1f96c0dd26c8289e7e7ce44f 100644 (file)
@@ -287,6 +287,95 @@ ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section
 ld::Section LazyPointerAtom::_s_sectionClose("__DATA", "__lazy_symbol", ld::Section::typeLazyPointerClose);
 
 
+class NonLazyPointerAtom : public ld::Atom {
+public:
+                                                                                       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, 
+                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &stubTo) {
+                                       pass.addAtom(*this);
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 4; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionClose;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class StubPICKextAtom : public ld::Atom {
+public:
+                                                                                       StubPICKextAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableIn, false, true, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _nonLazyPointer(pass, stubTo),
+                               _fixup1(0, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonLazyPointer),
+                               _fixup2(0, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(0, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+                               _fixup4(0, ld::Fixup::k4of4, ld::Fixup::kindStoreThumbLow16),
+                               _fixup5(4, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonLazyPointer),
+                               _fixup6(4, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup7(4, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+                               _fixup8(4, ld::Fixup::k4of4, ld::Fixup::kindStoreThumbHigh16) {
+                                       pass.addAtom(*this); 
+                                       asprintf((char**)&_name, "%s.stub", _stubTo.name());
+                               }
+  
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0x0c00f240); //      movw    ip, #lo(nlp - L1)
+                       OSWriteLittleInt32(&buffer[ 4], 0, 0x0c00f2c0); //      movt    ip, #hi(nlp - L1)
+                       OSWriteLittleInt16(&buffer[ 8], 0, 0x44fc);             //      add             ip, pc
+                       OSWriteLittleInt32(&buffer[10], 0, 0xc000f8dc); //      ldr.w   ip, [ip]
+                       OSWriteLittleInt16(&buffer[14], 0, 0x4760);             //      bx              ip
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup8)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       const char*                                                             _name;
+       NonLazyPointerAtom                                              _nonLazyPointer;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       ld::Fixup                                                               _fixup5;
+       ld::Fixup                                                               _fixup6;
+       ld::Fixup                                                               _fixup7;
+       ld::Fixup                                                               _fixup8;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubPICKextAtom::_s_section("__TEXT", "__stub", ld::Section::typeCode);
+
+
 
 class StubPICAtom : public ld::Atom {
 public:
index e74b37d40e75a68f35d29ead87bcce0297cdcccc..e3cebca9b9f2c32186e7871c42b1264bd5a98a3b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -362,5 +362,78 @@ ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
 
 
 
+
+class NonLazyPointerAtom : public ld::Atom {
+public:
+                                                                                       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, 
+                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _stubTo(stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
+                                       pass.addAtom(*this);
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+
+class KextStubAtom : public ld::Atom {
+public:
+                                                                                       KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo), 
+                               _nonLazyPointer(pass, stubTo),
+                               _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 6; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0] = 0xFF;               // jmp *foo$non_lazy_pointer(%rip)
+                       buffer[1] = 0x25;
+                       buffer[2] = 0x00;
+                       buffer[3] = 0x00;
+                       buffer[4] = 0x00;
+                       buffer[5] = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       NonLazyPointerAtom                                              _nonLazyPointer;
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
 } // namespace x86_64 
 
index aa4aaf12372eb50aa628fe16d5dd8e29bbbdb405..5ea1b05606cfa9ef6158a273c2963da38d0f2636 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "Options.h"
 #include "ld.hpp"
+#include "MachOFileAbstraction.hpp"
 
 #include "make_stubs.h"
 
@@ -118,6 +119,7 @@ const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
                        case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                assert(target != NULL);
                                // create stub if target is in a dylib
                                if ( target->definition() == ld::Atom::definitionProxy ) 
                                        return target;
@@ -175,20 +177,31 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
        }
 
        switch ( _architecture ) {
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( usingCompressedLINKEDIT() && !forLazyDylib )
                                return new ld::passes::stubs::x86::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        else
                                return new ld::passes::stubs::x86::classic::StubAtom(*this, target, forLazyDylib, weakImport);
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
-                       if ( usingCompressedLINKEDIT() && !forLazyDylib )
+                       if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
+                               return new ld::passes::stubs::x86_64::KextStubAtom(*this, target);
+                       else if ( usingCompressedLINKEDIT() && !forLazyDylib )
                                return new ld::passes::stubs::x86_64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        else
                                return new ld::passes::stubs::x86_64::classic::StubAtom(*this, target, forLazyDylib, weakImport);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM: 
-                       if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
+                       if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) {
+                               // if text relocs are not allows in kext bundles, then linker must create a stub 
+                               return new ld::passes::stubs::arm::StubPICKextAtom(*this, target);
+                       }
+                       else if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
                                if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
                                        return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                                else if ( _pic )
@@ -203,6 +216,7 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                                        return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
                        }
                        break;
+#endif
        }
        throw "unsupported arch for stub";
 }
@@ -226,7 +240,6 @@ void Pass::process(ld::Internal& state)
                case Options::kObjectFile:
                        // these kinds don't use stubs and can have resolver functions
                        return;
-               case Options::kKextBundle:
                case Options::kStaticExecutable:
                case Options::kPreload:
                case Options::kDyld:
@@ -236,6 +249,12 @@ void Pass::process(ld::Internal& state)
                case Options::kDynamicLibrary:
                        // uses stubs and can have resolver functions
                        break;
+               case Options::kKextBundle:
+                       verifyNoResolverFunctions(state);
+                       // if kext don't use stubs, don't do this pass
+                       if ( !_options.kextsUseStubs() )
+                               return;
+                       break;
                case Options::kDynamicExecutable:
                case Options::kDynamicBundle:
                        // these kinds do use stubs and cannot have resolver functions
@@ -302,6 +321,15 @@ void Pass::process(ld::Internal& state)
                        }
                }
        }
+
+       const bool needStubForMain = _options.needsEntryPointLoadCommand() 
+                                                               && (state.entryPoint != NULL) 
+                                                               && (state.entryPoint->definition() == ld::Atom::definitionProxy);
+       if ( needStubForMain ) {
+               // _main not found in any .o files.  Currently have proxy to dylib 
+               // Add to map, so that a stub will be made
+               stubFor[state.entryPoint] = NULL;       
+       }
        
        // short circuit if no stubs needed
        _internal = &state;
@@ -310,7 +338,7 @@ void Pass::process(ld::Internal& state)
                return;
        
        // <rdar://problem/8553283> lazily check for helper
-       if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) ) 
+       if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) && (_options.outputKind() != Options::kKextBundle) 
                throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
 
        // disable arm close stubs in some cases
@@ -357,6 +385,13 @@ void Pass::process(ld::Internal& state)
                }
        }
        
+       // switch entry point from proxy to stub
+       if ( needStubForMain ) {
+               const ld::Atom* mainStub = stubFor[state.entryPoint];   
+               assert(mainStub != NULL);
+               state.entryPoint = mainStub;
+       }
+       
        // sort new atoms so links are consistent
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
index 44d8f53f7e2987fef7af162c309367328836ac59..55e1068b7f429f90c4b5394f7a3eca7f2099cedb 100644 (file)
@@ -830,7 +830,25 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                        break;
                case ld::Fixup::kindSetLazyOffset:
                        printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
-                       break;                  
+                       break;
+               case ld::Fixup::kindDataInCodeStartData:
+                       printf("start of data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT8:
+                       printf("start of jump table 8 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT16:
+                       printf("start of jump table 16 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT32:
+                       printf("start of jump table 32 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJTA32:
+                       printf("start of jump table absolute 32 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeEnd:
+                       printf("end of data in code");
+                       break;
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                        printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
                        break;
@@ -1110,12 +1128,12 @@ static ld::relocatable::File* createReader(const char* path)
                }
        }
 
-       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
+       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), objOpts);
        if ( objResult != NULL )
                return objResult;
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, 0, sPreferredArch, sPreferredSubArch, false);
+       objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, sPreferredArch, sPreferredSubArch, false);
        if ( objResult != NULL ) 
                return objResult;
 
@@ -1183,24 +1201,20 @@ int main(int argc, const char* argv[])
                                        sShowLineInfo = false;
                                }
                                else if ( strcmp(arg, "-arch") == 0 ) {
-                                       const char* arch = ++i<argc? argv[i]: "";
-                                       if ( strcmp(arch, "i386") == 0 )
-                                               sPreferredArch = CPU_TYPE_I386;
-                                       else if ( strcmp(arch, "x86_64") == 0 )
-                                               sPreferredArch = CPU_TYPE_X86_64;
-                                       else {
-                                               bool found = false;
-                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
-                                                               sPreferredArch = CPU_TYPE_ARM;
-                                                               sPreferredSubArch = t->subType;
-                                                               found = true;
-                                                               break;
-                                                       }
+                                       const char* archName = argv[++i];
+                                       if ( archName == NULL )
+                                               throw "-arch missing architecture name";
+                                       bool found = false;
+                                       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                                               if ( strcmp(t->archName,archName) == 0 ) {
+                                                       sPreferredArch = t->cpuType;
+                                                       if ( t->isSubType )
+                                                               sPreferredSubArch = t->cpuSubType;
+                                                       found = true;
                                                }
-                                               if ( !found )
-                                                       throwf("unknown architecture %s", arch);
                                        }
+                                       if ( !found )
+                                               throwf("unknown architecture %s", archName);
                                }
                                else if ( strcmp(arg, "-only") == 0 ) {
                                        sMatchName = ++i<argc? argv[i]: NULL;
index 6a63ca18174aca63d27703aa5e81475aff1198ca..4ad006a7d7828a4c34232ee9ee8a3fd5edb49886 100644 (file)
@@ -38,6 +38,7 @@
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 #include "MachOTrie.hpp"
+#include "../ld/code-sign-blobs/superblob.h"
 
 static bool printRebase = false;
 static bool printBind = false;
@@ -50,6 +51,8 @@ static bool printExportNodes = false;
 static bool printSharedRegion = false;
 static bool printFunctionStarts = false;
 static bool printDylibs = false;
+static bool printDRs = false;
+static bool printDataCode = false;
 static cpu_type_t      sPreferredArch = 0;
 static cpu_type_t      sPreferredSubArch = 0;
 
@@ -110,6 +113,8 @@ private:
        void                                                                            printSharedRegionInfo();
        void                                                                            printFunctionStartsInfo();
        void                                                                            printDylibsInfo();
+       void                                                                            printDRInfo();
+       void                                                                            printDataInCode();
        void                                                                            printFunctionStartLine(uint64_t addr);
        const uint8_t*                                                          printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
        pint_t                                                                          relocBase();
@@ -143,6 +148,8 @@ private:
        const macho_dyld_info_command<P>*                       fInfo;
        const macho_linkedit_data_command<P>*           fSharedRegionInfo;
        const macho_linkedit_data_command<P>*           fFunctionStartsInfo;
+       const macho_linkedit_data_command<P>*           fDataInCode;
+       const macho_linkedit_data_command<P>*           fDRInfo;
        uint64_t                                                                        fBaseAddress;
        const macho_dysymtab_command<P>*                        fDynamicSymbolTable;
        const macho_segment_command<P>*                         fFirstSegment;
@@ -166,6 +173,7 @@ bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -184,6 +192,7 @@ bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -202,6 +211,7 @@ bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -220,6 +230,7 @@ bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -227,6 +238,7 @@ bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
        return false;
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
 {      
@@ -238,18 +250,20 @@ bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
        }
        return false;
 }
+#endif
 
 template <typename A>
 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
  : fHeader(NULL), fLength(fileLength), 
    fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), 
-   fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), 
+   fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL), 
    fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
    fWriteableSegmentWithAddrOver4G(false)
 {
@@ -332,32 +346,26 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                        case LC_FUNCTION_STARTS:
                                fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
                                break;
+                       case LC_DATA_IN_CODE:
+                               fDataInCode = (macho_linkedit_data_command<P>*)cmd;
+                               break;
+                       case LC_DYLIB_CODE_SIGN_DRS:
+                               fDRInfo = (macho_linkedit_data_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)endOfCmd;
        }
        
        if ( printArch ) {
-               switch ( fHeader->cputype() ) {
-                       case CPU_TYPE_I386:
-                               printf("for arch i386:\n");
-                               break;
-                       case CPU_TYPE_X86_64:
-                               printf("for arch x86_64:\n");
-                               break;
-                       case CPU_TYPE_POWERPC:                  
-                               printf("for arch ppc:\n");
-                               break;
-                       case CPU_TYPE_ARM:
-                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                       if ( (cpu_subtype_t)fHeader->cpusubtype() == t->subType) {
-                                               printf("for arch %s:\n", t->subTypeName);
-                                               break;
-                                       }
-                               }
+               for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                       if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
+                               if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
+                                       continue;
+                               printf("for arch %s:\n", t->archName);
+                       }
                }
        }
        
-       
        if ( printRebase ) {
                if ( fInfo != NULL )
                        printRebaseInfo();
@@ -400,6 +408,10 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                printFunctionStartsInfo();
        if ( printDylibs )
                printDylibsInfo();
+       if ( printDRs )
+               printDRInfo();
+       if ( printDataCode )
+               printDataInCode();
 }
 
 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
@@ -432,7 +444,7 @@ static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
                if (p == end)
                        throwf("malformed sleb128");
                byte = *p++;
-               result |= ((byte & 0x7f) << bit);
+               result |= (((int64_t)(byte & 0x7f)) << bit);
                bit += 7;
        } while (byte & 0x80);
        // sign extend negative numbers
@@ -1545,6 +1557,7 @@ void DyldInfoPrinter<A>::printSharedRegionInfo()
        }
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
 {
@@ -1553,6 +1566,7 @@ void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
        else
                printf("0x%0llX         %s\n", addr, symbolNameForAddress(addr)); 
 }
+#endif
 
 template <typename A>
 void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
@@ -1617,6 +1631,85 @@ void DyldInfoPrinter<A>::printDylibsInfo()
        }
 }
 
+template <typename A>
+void DyldInfoPrinter<A>::printDRInfo()
+{
+       if ( fDRInfo == NULL ) {
+               printf("no Designated Requirements info\n");
+       }
+       else {
+               printf("dylibs                 DRs\n");
+               const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
+               //const uint8_t* end   = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
+               typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
+               typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsSetBlob;
+               const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
+               if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
+                       if ( topBlob->count() == fDylibLoadCommands.size() ) {
+                               for(unsigned i=0; i < topBlob->count(); ++i) {
+                                       printf(" %-20s   ", fDylibs[i]);
+                                       const Security::BlobCore* item = topBlob->find(i);
+                                       if ( item != NULL ) {
+                                               const uint8_t* itemStart = (uint8_t*)item;
+                                               const uint8_t* itemEnd = itemStart + item->length();
+                                               for(const uint8_t* p=itemStart; p < itemEnd; ++p)
+                                                       printf("%02X ", *p);
+                                       }
+                                       else {
+                                               printf("no DR info");
+                                       }
+                                       printf("\n");
+                               }
+                       }
+                       else {
+                               fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
+                       }
+               }
+               else {
+                       fprintf(stderr, "superblob of DRs invalid\n");
+               }
+       }
+}
+
+
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printDataInCode()
+{
+       if ( fDataInCode == NULL ) {
+               printf("no data-in-code info\n");
+       }
+       else {
+               printf("offset      length  data-kind\n");
+               const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
+               const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
+               for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
+                       const char* kindStr = "???";
+                       switch ( p->kind() ) {
+                               case 1:
+                                       kindStr = "data";
+                                       break;
+                               case 2:
+                                       kindStr = "jumptable8";
+                                       break;
+                               case 3:
+                                       kindStr = "jumptable16";
+                                       break;
+                               case 4:
+                                       kindStr = "jumptable32";
+                                       break;
+                               case 5:
+                                       kindStr = "jumptable32absolute";
+                                       break;
+                       }
+                       printf("0x%08X  0x%04X  %s\n", p->offset(), p->length(), kindStr);
+               }
+       }
+}
+
+
 
 template <>
 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
@@ -1652,6 +1745,7 @@ x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
        return fFirstWritableSegment->vmaddr();
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
 {
@@ -1660,6 +1754,7 @@ arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
        else
                return fFirstSegment->vmaddr();
 }
+#endif
 
 
 template <>
@@ -1700,6 +1795,7 @@ const char*       DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
                return "??";
 }
        
+#if SUPPORT_ARCH_arm_any
 template <>
 const char*    DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
 {
@@ -1710,7 +1806,7 @@ const char*       DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
        else
                return "??";
 }
-       
+#endif
 
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
@@ -2001,12 +2097,14 @@ static void dump(const char* path)
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
+#if SUPPORT_ARCH_arm_any
                                        case CPU_TYPE_ARM:
                                                if ( DyldInfoPrinter<arm>::validFile(p + offset) ) 
                                                        DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
+#endif
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
@@ -2025,9 +2123,11 @@ static void dump(const char* path)
                else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
                        DyldInfoPrinter<x86_64>::make(p, length, path, false);
                }
+#if SUPPORT_ARCH_arm_any
                else if ( DyldInfoPrinter<arm>::validFile(p) ) {
                        DyldInfoPrinter<arm>::make(p, length, path, false);
                }
+#endif
                else {
                        throw "not a known file type";
                }
@@ -2041,6 +2141,7 @@ static void usage()
 {
        fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
                        "\t-dylibs           print dependent dylibs\n"
+                       "\t-dr               print dependent dylibs and show any recorded DR info\n"
                        "\t-rebase           print addresses dyld will adjust if file not loaded at preferred address\n"
                        "\t-bind             print addresses dyld will set based on symbolic lookups\n"
                        "\t-weak_bind        print symbols which dyld must coalesce\n"
@@ -2049,6 +2150,7 @@ static void usage()
                        "\t-opcodes          print opcodes used to generate the rebase and binding information\n"
                        "\t-function_starts  print table of function start addresses\n"
                        "\t-export_dot       print a GraphViz .dot file of the exported symbols trie\n"
+                       "\t-data_in_code     print any data-in-code inforamtion\n"
                );
 }
 
@@ -2076,17 +2178,19 @@ int main(int argc, const char* argv[])
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                sPreferredArch = CPU_TYPE_X86_64;
                                        else {
+                                               const char* archName = argv[++i];
+                                               if ( archName == NULL )
+                                                       throw "-arch missing architecture name";
                                                bool found = false;
-                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
-                                                               sPreferredArch = CPU_TYPE_ARM;
-                                                               sPreferredSubArch = t->subType;
-                                                               found = true;
-                                                               break;
+                                               for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                                                       if ( strcmp(t->archName,archName) == 0 ) {
+                                                               sPreferredArch = t->cpuType;
+                                                               if ( t->isSubType )
+                                                                       sPreferredSubArch = t->cpuSubType;
                                                        }
                                                }
                                                if ( !found )
-                                                       throwf("unknown architecture %s", arch);
+                                                       throwf("unknown architecture %s", archName);
                                        }
                                }
                                else if ( strcmp(arg, "-rebase") == 0 ) {
@@ -2122,6 +2226,12 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-dylibs") == 0 ) {
                                        printDylibs = true;
                                }
+                               else if ( strcmp(arg, "-dr") == 0 ) {
+                                       printDRs = true;
+                               }
+                               else if ( strcmp(arg, "-data_in_code") == 0 ) {
+                                       printDataCode = true;
+                               }
                                else {
                                        throwf("unknown option: %s\n", arg);
                                }
index 54dc560c1d21ea9d1020ef646e4da373181d1a76..36a71fd3232aa2b578a85c1c01714295817ae374 100644 (file)
@@ -388,6 +388,7 @@ void MachOChecker<A>::checkLoadCommands()
        // check that all load commands fit within the load command space file
        const macho_encryption_info_command<P>* encryption_info = NULL;
        const macho_thread_command<P>* threadInfo = NULL;
+       const macho_entry_point_command<P>* entryPoint = NULL;
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
        const uint32_t cmd_count = fHeader->ncmds();
@@ -424,8 +425,12 @@ void MachOChecker<A>::checkLoadCommands()
                        case LC_LOAD_UPWARD_DYLIB:
                        case LC_VERSION_MIN_MACOSX:
                        case LC_VERSION_MIN_IPHONEOS:
-                       case LC_FUNCTION_STARTS:
                        case LC_RPATH:
+                       case LC_FUNCTION_STARTS:
+                       case LC_DYLD_ENVIRONMENT:
+                       case LC_DATA_IN_CODE:
+                       case LC_DYLIB_CODE_SIGN_DRS:
+                       case LC_SOURCE_VERSION:
                                break;
                        case LC_DYLD_INFO:
                        case LC_DYLD_INFO_ONLY:
@@ -439,6 +444,11 @@ void MachOChecker<A>::checkLoadCommands()
                                if ( fHeader->flags() & MH_NO_REEXPORTED_DYLIBS )
                                        throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags should not be set in an image with LC_SUB_LIBRARY or LC_SUB_UMBRELLA";
                                break;
+                       case LC_MAIN:
+                               if ( fHeader->filetype() != MH_EXECUTE )
+                                       throw "LC_MAIN can only be used in MH_EXECUTE file types";
+                               entryPoint =  (macho_entry_point_command<P>*)cmd;
+                               break;
                        case LC_UNIXTHREAD:
                                if ( fHeader->filetype() != MH_EXECUTE )
                                        throw "LC_UNIXTHREAD can only be used in MH_EXECUTE file types";
@@ -590,7 +600,11 @@ void MachOChecker<A>::checkLoadCommands()
                if ( (initialPC < fTEXTSegment->vmaddr()) ||  (initialPC >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) 
                        throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialPC);
        }
-       
+       else if ( entryPoint != NULL ) {
+               pint_t initialOffset = entryPoint->entryoff();
+               if ( (initialOffset < fTEXTSegment->fileoff()) ||  (initialOffset >= (fTEXTSegment->fileoff()+fTEXTSegment->filesize())) ) 
+                       throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialOffset);
+       }
        
        // checks for executables
        bool isStaticExecutable = false;
@@ -607,7 +621,7 @@ void MachOChecker<A>::checkLoadCommands()
                        cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
                }
                if ( isStaticExecutable ) {
-                       if ( fHeader->flags() != MH_NOUNDEFS )
+                       if ( (fHeader->flags() != MH_NOUNDEFS) && (fHeader->flags() != (MH_NOUNDEFS|MH_PIE)) )
                                throw "invalid bits in mach_header flags for static executable";
                }
        }
@@ -661,7 +675,7 @@ void MachOChecker<A>::checkLoadCommands()
                                break;
                        case LC_DYSYMTAB:
                                {
-                                       if ( isStaticExecutable )
+                                       if ( isStaticExecutable &&! fSlidableImage )
                                                throw "LC_DYSYMTAB should not be used in static executable";
                                        foundDynamicSymTab = true;
                                        fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
@@ -725,6 +739,32 @@ void MachOChecker<A>::checkLoadCommands()
                                                throw "function starts data size not a multiple of pointer size";
                                }
                                break;
+                       case LC_DATA_IN_CODE:
+                               {
+                                       const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+                                       if ( info->dataoff() < linkEditSegment->fileoff() )
+                                               throw "data-in-code data not in __LINKEDIT";
+                                       if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "data-in-code data not in __LINKEDIT";
+                                       if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+                                               throw "data-in-code data table not pointer aligned";
+                                       if ( (info->datasize() % sizeof(pint_t)) != 0 )
+                                               throw "data-in-code data size not a multiple of pointer size";
+                               }
+                               break;
+                       case LC_DYLIB_CODE_SIGN_DRS:
+                               {
+                                       const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+                                       if ( info->dataoff() < linkEditSegment->fileoff() )
+                                               throw "dependent dylib DR data not in __LINKEDIT";
+                                       if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "dependent dylib DR  data not in __LINKEDIT";
+                                       if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+                                               throw "dependent dylib DR  data table not pointer aligned";
+                                       if ( (info->datasize() % sizeof(pint_t)) != 0 )
+                                               throw "dependent dylib DR  data size not a multiple of pointer size";
+                               }
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
@@ -1039,6 +1079,7 @@ void MachOChecker<x86_64>::checkExternalReloation(const macho_relocation_info<P>
        // FIX: check r_symbol
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 void MachOChecker<arm>::checkExternalReloation(const macho_relocation_info<P>* reloc)
 {
@@ -1054,6 +1095,7 @@ void MachOChecker<arm>::checkExternalReloation(const macho_relocation_info<P>* r
                throw "external relocation address not in writable segment";
        // FIX: check r_symbol
 }
+#endif
 
 
 template <>
@@ -1109,6 +1151,7 @@ void MachOChecker<x86_64>::checkLocalReloation(const macho_relocation_info<P>* r
                throw "local relocation address not in writable segment";
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 void MachOChecker<arm>::checkLocalReloation(const macho_relocation_info<P>* reloc)
 {
@@ -1129,6 +1172,7 @@ void MachOChecker<arm>::checkLocalReloation(const macho_relocation_info<P>* relo
                        throw "local relocation address not in writable segment";
        }
 }
+#endif
 
 template <typename A>
 void MachOChecker<A>::checkRelocations()
@@ -1273,6 +1317,7 @@ bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
                        }
                }       
        }
+       return false;
 }
 
 template <typename A>
@@ -1518,12 +1563,14 @@ static void check(const char* path)
                                        else
                                                throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                        break;
+#if SUPPORT_ARCH_arm_any
                                case CPU_TYPE_ARM:
                                        if ( MachOChecker<arm>::validFile(p + offset) )
                                                MachOChecker<arm>::make(p + offset, size, path);
                                        else
                                                throw "in universal file, arm slice does not contain arm mach-o";
                                        break;
+#endif
                                default:
                                                throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                }
@@ -1541,9 +1588,11 @@ static void check(const char* path)
                else if ( MachOChecker<x86_64>::validFile(p) ) {
                        MachOChecker<x86_64>::make(p, length, path);
                }
+#if SUPPORT_ARCH_arm_any
                else if ( MachOChecker<arm>::validFile(p) ) {
                        MachOChecker<arm>::make(p, length, path);
                }
+#endif
                else {
                        throw "not a known file type";
                }
index 2255789436f2303f6ea371a1a8fe0941219a6228..d1e319408f31d38de08c05be100c8494424f2870 100644 (file)
@@ -674,6 +674,7 @@ void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
        }
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 void Rebaser<arm>::doLocalRelocation(const macho_relocation_info<P>* reloc)
 {
@@ -693,6 +694,7 @@ void Rebaser<arm>::doLocalRelocation(const macho_relocation_info<P>* reloc)
                }
        }
 }
+#endif
 
 template <typename A>
 void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
@@ -1008,27 +1010,18 @@ int main(int argc, const char* argv[])
                                        highAddress = strtoull(argv[++i], &endptr, 16);
                                }
                                else if ( strcmp(arg, "-arch") == 0 ) {
-                                       const char* arch = argv[++i];
-                                       if ( strcmp(arch, "ppc") == 0 ) 
-                                               onlyArchs.insert(CPU_TYPE_POWERPC);
-                                       else if ( strcmp(arch, "ppc64") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_POWERPC64);
-                                       else if ( strcmp(arch, "i386") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_I386);
-                                       else if ( strcmp(arch, "x86_64") == 0 )
-                                               onlyArchs.insert(CPU_TYPE_X86_64);
-                                       else {
-                                               bool found = false;
-                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
-                                                               onlyArchs.insert(CPU_TYPE_ARM);
-                                                               found = true;
-                                                               break;
-                                                       }
+                                       const char* archName = argv[++i];
+                                       if ( archName == NULL )
+                                               throw "-arch missing architecture name";
+                                       bool found = false;
+                                       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                                               if ( strcmp(t->archName,archName) == 0 ) {
+                                                       onlyArchs.insert(t->cpuType);
+                                                       found = true;
                                                }
-                                               if ( !found )
-                                                       throwf("unknown architecture %s", arch);
                                        }
+                                       if ( !found )
+                                               throwf("unknown architecture %s", archName);
                                }
                                else {
                                        usage();
index f860985b8de5b3c9ec94ce19f2698a758ec428a5..0d681ba4ed00cc5c11f92e56867f044469c23017 100755 (executable)
@@ -4,6 +4,7 @@ use strict;
 use Data::Dumper;
 use File::Find;
 use Cwd qw(realpath);
+use English;
 
 my @args = @ARGV;
 
@@ -31,6 +32,17 @@ my $keywords =
     'stderr' => [],
 };
 
+# Determine how many tests to run at a time in parallel. Default to cpu count.
+my $max_concurrent_tests = $ENV{'LD_UNIT_TEST_CONCURRENCY'};
+if (!defined $max_concurrent_tests) {
+    # shell command returns cpu count in exit status
+    system("/bin/csh", "-c", "set n=`sysctl hw.ncpu`; exit \$n[2]");
+    if ($? == -1 || $? & 127) {
+        die("could not determine cpu count");
+    }
+    $max_concurrent_tests = $? >> 8;
+}
+
 my $keyword;
 my $max_keyword_len = 0;
 foreach $keyword (keys %$keywords)
@@ -42,82 +54,117 @@ my $last_keyword = '';
 
 sub print_line
 {
-    my ($keyword, $val) = @_;
-
+    my ($file, $keyword, $val) = @_;
+    
     if(!exists($$keywords{$keyword}))
     {
-       print STDERR "error: keyword $keyword not in \$keywords set\n";
-       exit(1);
+        print STDERR "error: keyword $keyword not in \$keywords set\n";
+        exit(1);
     }
-
+    
     my $keyword_len = 0;
-
+    
     if($keyword ne $last_keyword)
     {
-       print("$keyword"); print($delim);
-       $keyword_len = length($keyword) + length($delim);
+        print($file "$keyword"); print($file $delim);
+        $keyword_len = length($keyword) + length($delim);
     }
     if($max_keyword_len > $keyword_len)
     {
-       my $num_spaces = $max_keyword_len - $keyword_len;
-       print(' ' x $num_spaces);
+        my $num_spaces = $max_keyword_len - $keyword_len;
+        print($file ' ' x $num_spaces);
     }
-    print("$val");
+    print($file "$val");
     if(0)
     {
-       $last_keyword = $keyword;
+        $last_keyword = $keyword;
     }
 }
 
 my $root = '.';
 $root = &realpath($root);
-print_line("root", "$root\n");
-
+print_line(*STDOUT, "root", "$root\n");
+my $running_test_count=0;
 find($find_opts, $root);
+while ( $running_test_count > 0 ) {
+    &reaper;
+}
 
 sub find_callback
 {
     if(exists($$makefiles{$_}))
     {
-       my $makefile = $_;
-       my $reldir = $File::Find::dir;
-       $reldir =~ s|^$root/||;
-       
-       &print_line("cwd", "\$root/$reldir\n");
-       my $cmd = [ "make" ];
-       
-       my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this?
-       &print_line("cmd", "@$cmd\n");
-
-        open(SAVEOUT, ">&STDOUT") || die("$!");
-        open(SAVEERR, ">&STDERR") || die("$!");
-       open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!");
-       open(STDERR, ">/tmp/unit-tests-stderr") || die("$!");
-
-       $ENV{UNIT_TEST_NAME} = $reldir;
-       my $exit = system(@$cmd);
-
-       close(STDOUT) || die("$!");
-       close(STDERR) || die("$!");
-        open(STDOUT, ">&SAVEOUT") || die("$!");
-        open(STDERR, ">&SAVEERR") || die("$!");
-
-       &print_line("exit", "$exit\n");
+        my $makefile = $_;
+        my $reldir = $File::Find::dir;
+        $reldir =~ s|^$root/||;
+        
+        my $cmd = [ "make" ];
+        
+        my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this?
+        
+        $ENV{UNIT_TEST_NAME} = $reldir;
+        my $pid = fork();
+        if (not defined $pid) {
+            die "Couldn't fork"
+        }
+        elsif ($pid == 0) {
+            # Child. Redirect stdout/stderr to files and exec test.
+            open(STDOUT, ">/tmp/unit-tests-stdout.$PID") || die("$!");
+            open(STDERR, ">/tmp/unit-tests-stderr.$PID") || die("$!");
+            exec 'make', @ARGV;
+            exit(-1);    #just to be sure
+        }
+        
+        # Write the test cwd/cmd to a temporary file associated with the child's pid, to be retrieved later.
+        my $info;
+        open($info, ">/tmp/unit-tests-info.$pid") || die("$!");
+        &print_line($info, "cwd", "\$root/$reldir\n"); # post filtering depends on this line being first
+        &print_line($info, "cmd", "@$cmd\n");
+        close($info) || die("$!");
+        
+        $running_test_count++;
+        # if we have reached max # of concurrent tests, wait for one to exit
+        if ( $running_test_count == $max_concurrent_tests ) {
+            &reaper;
+        }
+    }
+}
 
-       open(OUT, "</tmp/unit-tests-stdout") || die("$!");
-       while(<OUT>)
-       {
-           &print_line("stdout", "$_");
-       }
-       close(OUT) || die("$!");
-       unlink("/tmp/unit-tests-stdout");
-       
-       open(ERR, "</tmp/unit-tests-stderr") || die("$!");
-       while(<ERR>)
-       {
-           &print_line("stderr", "$_");
+sub reaper {
+       if ( $running_test_count > 0 ) {
+               my $pid = wait;
+        if ( $pid == -1 ) {
+            die("no child\n");
+        }
+        my $exit = $?;
+        
+               $running_test_count--;
+        
+               open(INFO, "</tmp/unit-tests-info.$pid") || die("$!");
+               while(<INFO>)
+               {
+            print $_;
+               }
+               close(INFO) || die("$!");
+               unlink("/tmp/unit-tests-info.$pid");
+        
+        &print_line(*STDOUT, "exit", "$exit\n");
+        
+               open(OUT, "</tmp/unit-tests-stdout.$pid") || die("$!");
+               while(<OUT>)
+               {
+                   &print_line(*STDOUT, "stdout", "$_");
+               }
+               close(OUT) || die("$!");
+               unlink("/tmp/unit-tests-stdout.$pid");
+        
+               open(ERR, "</tmp/unit-tests-stderr.$pid") || die("$!");
+               while(<ERR>)
+               {
+                   &print_line(*STDOUT, "stderr", "$_");
+               }
+               close(ERR) || die("$!");
+               unlink("/tmp/unit-tests-stderr.$pid");
        }
-       close(ERR) || die("$!");
-    }
-       unlink("/tmp/unit-tests-stderr");
 }
+
index adb5468c1fba2b271daf573e85a2ee17bebefd71..97864cae24df1b4a2749340d726539b3931fbdf9 100644 (file)
@@ -8,7 +8,6 @@ ARCH ?= $(shell arch)
 # set default to be all
 VALID_ARCHS ?= "i386 x86_64 armv6"
 
-IOS_SDK = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.Internal.sdk
 
 MYDIR=$(shell cd ../../bin;pwd)
 LD                     = ld
@@ -56,21 +55,23 @@ ifeq ($(ARCH),ppc)
        SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
 endif
 
-CC              = cc -arch ${ARCH} ${SDKExtra}
+CC              = $(shell xcrun -find clang) -arch ${ARCH} ${SDKExtra}
 CCFLAGS = -Wall 
 ASMFLAGS =
 VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
 VERSION_OLD_LINKEDIT = -mmacosx-version-min=10.4
 LD_NEW_LINKEDIT = -macosx_version_min 10.6
 
-CXX              = c++ -arch ${ARCH} ${SDKExtra}
+CXX              = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall
 
+IOS_SDK = $(shell xcodebuild -sdk iphoneos6.0.internal -version Path)
+
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
-  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
-  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
@@ -82,8 +83,8 @@ endif
 ifeq ($(ARCH),armv7)
   LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
-  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
-  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
@@ -98,8 +99,8 @@ ifeq ($(ARCH),thumb)
   CXXFLAGS += -mthumb
   override ARCH = armv6
   override FILEARCH = arm
-  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
-  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
@@ -114,8 +115,8 @@ ifeq ($(ARCH),thumb2)
   CXXFLAGS += -mthumb
   override ARCH = armv7
   override FILEARCH = arm
-  CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
-  CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
index c07c947d5ecb63cb5b9252e7789c8308c5b4ef87..92851281512dcba73c398be50713cb6b274341e0 100755 (executable)
@@ -15,7 +15,7 @@ cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 all_archs="x86_64  i386"
 valid_archs="x86_64 i386"
 # only test arm code if iOS platform tools installed
-if [ -d /Developer/Platforms/iPhoneOS.platform/Developer/SDKs ]
+if [ -d /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs ]
 then
     all_archs="${all_archs}  armv7"
     valid_archs="${valid_archs} armv7"
index e178ddb02e110d092265a6bf6527bd76b6638dbf..533e222dbb168e9e46d8d0a95639c779a88dcd75 100644 (file)
@@ -33,11 +33,11 @@ all:
        ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -c -O2 tl_test2.c -o tl_test2-${ARCH}.o
 
        # verify that the alignment is correct in the .o
-       ${OBJECTDUMP} -only _ai -align -no_content tl_test2-${ARCH}.o|${FAIL_IF_ERROR} grep '\<0 mod 16\>' >/dev/null
+       ${OBJECTDUMP} -only _ai -align -no_content tl_test2-${ARCH}.o|${FAIL_IF_ERROR} grep '0 mod 16' >/dev/null
 
        # now verify the executable
        ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -arch ${ARCH} -O2 tl_test2-${ARCH}.o -o tl_test2-${ARCH}
-       ${FAIL_IF_ERROR} sh -c "nm tl_test2-${ARCH}|grep '0 D _ai\>' >/dev/null"
+       ${FAIL_IF_ERROR} sh -c "nm tl_test2-${ARCH}|grep '0 D _ai' >/dev/null"
        ${PASS_IFF_GOOD_MACHO} tl_test2-${ARCH}
 
 clean:
diff --git a/unit-tests/test-cases/archive-r-ObjC/Makefile b/unit-tests/test-cases/archive-r-ObjC/Makefile
new file mode 100644 (file)
index 0000000..939d8a9
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# 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
+
+#
+# The point of this test is to check that -ObjC loads all (and only)
+# .o files that contain Objective-C code that has gone through ld -r.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.m -c -o foo.o 
+       ${LD} -r -arch ${ARCH} foo.o -o foo-r.o
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o 
+       ${LD} -r -arch ${ARCH} bar.o -o bar-r.o
+       ${CC} ${CCFLAGS} baz.m -c -o baz.o 
+       ${LD} -r -arch ${ARCH} baz.o -o baz-r.o
+       ${CC} ${CCFLAGS} cat.m -c -o cat.o 
+       ${LD} -r -arch ${ARCH} cat.o -o cat-r.o
+       libtool -static foo-r.o bar-r.o baz-r.o cat-r.o -o liball.a
+       ${CC} ${CCFLAGS} main.c liball.a -o main -ObjC -framework Foundation -framework CoreFoundation
+       ${FAIL_IF_BAD_MACHO} main
+       nm main | grep "_bar" | ${FAIL_IF_STDIN}
+       nm main | grep "_Foo" | ${FAIL_IF_EMPTY}
+       nm main | grep "_Baz" | ${FAIL_IF_EMPTY}
+       nm main | grep "_mycatfunc" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main *.o *.a
diff --git a/unit-tests/test-cases/archive-r-ObjC/bar.c b/unit-tests/test-cases/archive-r-ObjC/bar.c
new file mode 100644 (file)
index 0000000..d9b468b
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar() { return 0; }
diff --git a/unit-tests/test-cases/archive-r-ObjC/baz.m b/unit-tests/test-cases/archive-r-ObjC/baz.m
new file mode 100644 (file)
index 0000000..90ae0a1
--- /dev/null
@@ -0,0 +1,8 @@
+#include <Foundation/Foundation.h>
+
+@interface Baz : NSObject
+@end
+
+@implementation Baz
+@end
+
diff --git a/unit-tests/test-cases/archive-r-ObjC/cat.m b/unit-tests/test-cases/archive-r-ObjC/cat.m
new file mode 100644 (file)
index 0000000..aaabfe3
--- /dev/null
@@ -0,0 +1,16 @@
+#include <Foundation/Foundation.h>
+
+@interface NSObject(Cat)
+@end
+
+@implementation NSObject(Cat)
+@end
+
+@interface NSObject(Dog)
+@end
+
+@implementation NSObject(Dog)
+@end
+
+void mycatfunc() {}
+
diff --git a/unit-tests/test-cases/archive-r-ObjC/foo.m b/unit-tests/test-cases/archive-r-ObjC/foo.m
new file mode 100644 (file)
index 0000000..acba7a4
--- /dev/null
@@ -0,0 +1,8 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
diff --git a/unit-tests/test-cases/archive-r-ObjC/main.c b/unit-tests/test-cases/archive-r-ObjC/main.c
new file mode 100644 (file)
index 0000000..dc2fbef
--- /dev/null
@@ -0,0 +1,31 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+       return 0;
+}
index 471e44669f073fa86556ee74703a422914e57e8b..8e1870b7c1575c740fdb8cc1d2797f0c4c36f504 100644 (file)
@@ -32,8 +32,12 @@ run: all
 
 
 all:
+       # Verify that we fail if there is no valid place to insert branch islands.
+       ${CC} ${CCFLAGS} hello.c atomic_space.s extra.c -o hello ${ARCH_FLAGS} 2>&1 | grep "Unable to insert branch island. No insertion point available." | ${PASS_IFF_STDIN}
+
        ${CC} ${CCFLAGS} hello.c space.s extra.c -o hello ${ARCH_FLAGS}
        ${PASS_IFF_GOOD_MACHO} hello
 
+
 clean:
        rm  hello
diff --git a/unit-tests/test-cases/branch-islands/atomic_space.s b/unit-tests/test-cases/branch-islands/atomic_space.s
new file mode 100644 (file)
index 0000000..4402d66
--- /dev/null
@@ -0,0 +1,76 @@
+
+#if __ppc__ 
+
+    .text
+
+_prejunk:
+    mr  r3,r5
+    mr  r3,r4
+    blr
+
+
+_space1:
+    .space 15*1024*1024 + 2
+    
+    .align 5
+_junk:
+    mr  r3,r5
+    mr  r3,r4
+    blr
+    
+    
+_space2:
+    .space 2*1024*1024
+#endif
+
+
+#if __arm__
+
+    .text
+_prejunk:
+    mov        r0, #1
+    nop
+
+#if __thumb2__
+       // thumb2 branches are +/- 16MB
+_space1:
+    .space 14*1024*1024
+_space2:
+    .space 14*1024*1024
+_space3:
+    .space 14*1024*1024
+
+
+#elif __thumb__
+       // thumb1 branches are +/- 4MB
+_space1:
+    .space 3*1024*1024
+_space2:
+    .space 3*1024*1024
+_space3:
+    .space 3*1024*1024
+    
+#else
+
+       // ARM branches are +/- 32MB
+_space1:
+    .space 14*1024*1024
+_space2:
+    .space 14*1024*1024
+_space3:
+    .space 14*1024*1024
+
+#endif
+
+    .align 5
+_junk:
+    mov        r0, #1
+    nop
+    
+    
+_space4:
+    .space 2*1024*1024
+#endif
+
+    //.subsections_via_symbols
diff --git a/unit-tests/test-cases/data-in-code/Makefile b/unit-tests/test-cases/data-in-code/Makefile
new file mode 100644 (file)
index 0000000..0897726
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# 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 L$start$.. labels are tracked
+#
+
+all: 
+       ${CC} ${CCFLAGS} -c test.s -o test.o
+       ${LD} -r -arch ${ARCH} test.o -o test2.o
+       #nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
+       #${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf test.o test2.o
diff --git a/unit-tests/test-cases/data-in-code/main.c b/unit-tests/test-cases/data-in-code/main.c
new file mode 100644 (file)
index 0000000..811449a
--- /dev/null
@@ -0,0 +1,49 @@
+
+#include <stdio.h>
+
+#define DTRACE_STRINGIFY(s) #s
+#define DTRACE_TOSTRING(s) DTRACE_STRINGIFY(s)
+
+#define DTRACE_NOPS                    \
+       "nop"                   "\n\t"  \
+       "nop"                   "\n\t"  \
+       "nop"                   "\n\t"  
+
+
+#define DTRACE_LAB(p, n)               \
+   "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
+
+#define DTRACE_LABEL(p, n)             \
+      ".section __DATA, __data\n\t"    \
+      ".globl " DTRACE_LAB(p, n) "\n\t"        \
+       DTRACE_LAB(p, n) ":\n\t" ".long 1f""\n\t"       \
+       ".text" "\n\t"                  \
+       "1:"
+
+#define DTRACE_CALL(p,n)       \
+       DTRACE_LABEL(p,n)       \
+       DTRACE_NOPS
+
+#define DTRACE_CALL0ARGS(provider, name)                                                       \
+       __asm volatile (                                                                                \
+                     DTRACE_CALL(provider, name)                                               \
+                     :                                                                         \
+                     :                                                                         \
+       );
+
+int deadwood()
+{
+       DTRACE_CALL0ARGS(__foo__, test2)
+       return 0;
+}
+
+
+int main() {
+       int a = 1;
+
+       while(a) {
+               DTRACE_CALL0ARGS(__foo__, test1)
+       }
+
+       return 0;
+}
diff --git a/unit-tests/test-cases/data-in-code/test.s b/unit-tests/test-cases/data-in-code/test.s
new file mode 100644 (file)
index 0000000..8dc92b8
--- /dev/null
@@ -0,0 +1,25 @@
+
+       .text
+       
+_foo:
+       nop
+       nop
+l$start$data$1:
+       nop
+       nop
+       nop
+l$start$jt8$2:
+       nop
+       nop
+l$start$jt16$3: 
+       nop
+       nop
+l$start$code$n4:
+       nop
+       nop
+       
+       
+       
+       .subsections_via_symbols
+       
+       
\ No newline at end of file
diff --git a/unit-tests/test-cases/duplicate_symbols/Makefile b/unit-tests/test-cases/duplicate_symbols/Makefile
new file mode 100644 (file)
index 0000000..a16e69b
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2007-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
+
+#
+# Check that multiple duplicate symbols are reported.
+#
+
+all:
+       ${CC} -arch ${ARCH} -c main_extern.c
+       ${CC} -arch ${ARCH} -c main_no_extern.c
+       ${CC} -arch ${ARCH} -c duplicates.c
+       ${CC} -arch ${ARCH} -dynamiclib -o duplicates.dylib duplicates.o 
+       libtool -static -o duplicates.a duplicates.o
+
+       # simple case of directly linking duplicates should fail
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main_extern.o duplicates.o 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_EMPTY}
+
+
+       # duplicates in a dylib succeed
+       ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} main_extern.o duplicates.dylib 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_STDIN}
+
+       # static lib - only fail if module containing duplicate symbols is actually referenced
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main_extern.o duplicates.a 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} main_no_extern.o duplicates.a 2>&1 | grep "2 duplicate symbols" | ${FAIL_IF_STDIN}
+
+       # simple case should succeed if we dead strip because none of the duplicates are referenced
+       ${FAIL_IF_ERROR} ${CC} ${CCFLAGS} -dead_strip main_extern.o duplicates.o 
+
+       rm -f a.out *.o *.a *.dylib
+       ${PASS_IFF} true
diff --git a/unit-tests/test-cases/duplicate_symbols/duplicates.c b/unit-tests/test-cases/duplicate_symbols/duplicates.c
new file mode 100644 (file)
index 0000000..2a62979
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+void a() {
+}
+
+void b() {
+}
+
+void c() {
+}
diff --git a/unit-tests/test-cases/duplicate_symbols/main_extern.c b/unit-tests/test-cases/duplicate_symbols/main_extern.c
new file mode 100644 (file)
index 0000000..b78ea48
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+This file references an extern function c() that lives in
+a separate compilation unit that also has a() and b().
+*/
+
+extern void c();
+
+void a() {
+}
+
+void b() {
+}
+
+int main() {
+c();
+}
diff --git a/unit-tests/test-cases/duplicate_symbols/main_no_extern.c b/unit-tests/test-cases/duplicate_symbols/main_no_extern.c
new file mode 100644 (file)
index 0000000..cbdbeb6
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+This file contains symbols that are duplicated in another file,
+but does not reference anything that would pull in the duplicates.
+*/
+
+void a() {
+}
+
+void b() {
+}
+
+int main() {
+}
diff --git a/unit-tests/test-cases/dylib-main/Makefile b/unit-tests/test-cases/dylib-main/Makefile
new file mode 100644 (file)
index 0000000..f01ef41
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a program can have is "main" in a dylib
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib
+       ${CC} ${CCFLAGS} foo.c libmain.dylib -o main -Wl,-new_main
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf libmain.dylib main
diff --git a/unit-tests/test-cases/dylib-main/foo.c b/unit-tests/test-cases/dylib-main/foo.c
new file mode 100644 (file)
index 0000000..85e6cd8
--- /dev/null
@@ -0,0 +1 @@
+void foo() {}
diff --git a/unit-tests/test-cases/dylib-main/main.c b/unit-tests/test-cases/dylib-main/main.c
new file mode 100644 (file)
index 0000000..a444c65
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/force-weak/Makefile b/unit-tests/test-cases/force-weak/Makefile
new file mode 100644 (file)
index 0000000..4dbf4e9
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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
+
+#
+# Check that forcing a symbol weak does not cause spurious warnings
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c test.c -dynamiclib -o libtest.dylib -Wl,-force_symbols_weak_list,weak.exp
+       otool -Iv libtest.dylib | grep _foo | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+       rm  libtest.dylib
diff --git a/unit-tests/test-cases/force-weak/foo.c b/unit-tests/test-cases/force-weak/foo.c
new file mode 100644 (file)
index 0000000..485aed6
--- /dev/null
@@ -0,0 +1,2 @@
+
+int foo = 5;
\ No newline at end of file
diff --git a/unit-tests/test-cases/force-weak/test.c b/unit-tests/test-cases/force-weak/test.c
new file mode 100644 (file)
index 0000000..bd0da12
--- /dev/null
@@ -0,0 +1,5 @@
+
+extern int foo;
+
+int getfoo() { return foo; }
+
diff --git a/unit-tests/test-cases/force-weak/weak.exp b/unit-tests/test-cases/force-weak/weak.exp
new file mode 100644 (file)
index 0000000..33c5f68
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+
diff --git a/unit-tests/test-cases/install-name-override/Makefile b/unit-tests/test-cases/install-name-override/Makefile
new file mode 100644 (file)
index 0000000..d4cfe56
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# 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
+
+
+#
+# verify $ld$install_name$osXX$/new/path overides install_name
+# 
+
+FORCE_MIN_OS_VERSION = -mmacosx-version-min=10.5
+
+ifeq ($(FILEARCH),arm)
+       FORCE_MIN_OS_VERSION = -miphoneos-version-min=4.0
+endif
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name /usr/local/lib/libfoo.dylib
+       otool -L libfoo.dylib | grep /usr/local/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       otool -L main | grep /usr/local/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o mainAlt ${FORCE_MIN_OS_VERSION}
+       otool -L mainAlt | grep /usr/lib/libfoo.dylib | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+       rm -f libfoo.dylib main mainAlt
diff --git a/unit-tests/test-cases/install-name-override/foo.c b/unit-tests/test-cases/install-name-override/foo.c
new file mode 100644 (file)
index 0000000..1a68260
--- /dev/null
@@ -0,0 +1,18 @@
+
+int foo()
+{
+       return 0;
+}
+
+                       
+#if __arm__ 
+       #define INSTALL_NAME_4_0(sym) \
+                 extern const char install_name_4_0 __asm("$ld$install_name$os4.0$" #sym ); const char install_name_4_0 = 0;
+                               
+       INSTALL_NAME_4_0(/usr/lib/libfoo.dylib)
+#else
+       #define INSTALL_NAME_10_5(sym) \
+                 extern const char install_name_10_5 __asm("$ld$install_name$os10.5$" #sym ); const char install_name_10_5 = 0;
+                               
+       INSTALL_NAME_10_5(/usr/lib/libfoo.dylib)
+#endif
diff --git a/unit-tests/test-cases/install-name-override/main.c b/unit-tests/test-cases/install-name-override/main.c
new file mode 100644 (file)
index 0000000..7f346c1
--- /dev/null
@@ -0,0 +1,9 @@
+
+extern int foo();
+
+int main()
+{
+  foo();
+  return 0;
+}
+
index 8f33f3632280d4d7941e829a723c316970cfdf4d..bd2150ceb3ba6f26f9f2edafeaf476deaee08cf6 100644 (file)
@@ -32,12 +32,6 @@ LLVMAR  = /usr/local/bin/llvm-ar
 #
 # Test the we set the stack execution bit properly.
 
-run:
-       if [ -f /Developer/usr/bin/llvm-gcc-4.2 ] ; then \
-         $(MAKE) all ; \
-       else \
-         ${PASS_IFF} /usr/bin/true ; \
-       fi
 
 all: zero one two three four five six seven eight nine ten \
     eleven twelve thirteen fourteen fifteen sixteen seventeen \
diff --git a/unit-tests/test-cases/lto-dead_strip-inline-asm/Makefile b/unit-tests/test-cases/lto-dead_strip-inline-asm/Makefile
new file mode 100644 (file)
index 0000000..35a0220
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# 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
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# <rdar://problem/11124216> [lto] Linking libLTO.dylib causing an assertion in ld
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto bar.c  -c -o bar.o
+       ${CC} ${CCFLAGS} bar.o -dynamiclib -o libbar.dylib -dead_strip -Wl,-exported_symbol,_bar
+       ${PASS_IFF_GOOD_MACHO} libbar.dylib
+       
+clean:
+       rm -f bar.o libbar.dylib
+       
diff --git a/unit-tests/test-cases/lto-dead_strip-inline-asm/bar.c b/unit-tests/test-cases/lto-dead_strip-inline-asm/bar.c
new file mode 100644 (file)
index 0000000..2b49dc1
--- /dev/null
@@ -0,0 +1,14 @@
+
+
+void qux() {}
+
+asm("\t.text\n"
+    "\t.globl _foo\n"
+    "_foo:\n"
+    "\tnop\n");
+
+extern void foo();
+
+void (*bar())() {
+  return foo;
+}
index 82192f8d4daa7a86960e3458e858db8cc4253234..79a193fa4a36debe2f53f24b0a43eb2ae5be7072 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+SHELL = bash # use bash shell so we can redirect just stderr
 
 #
 # <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
@@ -36,6 +37,8 @@ all:
        ${CC} ${CCFLAGS} -flto main.c -c -o main.o 
        ${CC} ${CCFLAGS} main.o bar.o -o main
        ${CC} ${CCFLAGS} main.o bar.o -o main -dead_strip 
+       ${CC} ${CCFLAGS} main.o bar.o -dynamiclib -o libmain.dylib -Wl,-exported_symbol,_main
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.o bar.o -dynamiclib -o libmain.dylib -dead_strip 2>/dev/null
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
index 063bc332ae37573d5e96e64527591f040bc158f9..6f9cc2c4b4f861657537c4f83ef0f3b05c82c800 100644 (file)
@@ -27,16 +27,13 @@ include ${TESTROOT}/include/common.makefile
 # verify -preload -pie produces relocations
 #
 
-LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
-LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH}
-
 run: all
 
 all:
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm a.c -c -o a.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm b.c -c -o b.o
-       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o
-       ${LLVMGCC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -Wl,-pie -o main.preload \
+       ${CC} ${CCFLAGS} -flto a.c -c -o a.o
+       ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -Wl,-pie -o main.preload \
                -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 
        otool -rv main.preload | grep "Local relocation information" | ${PASS_IFF_STDIN}
 
index 7c5304bd090343ef0ed094f48f87a94cc0f422fb..dcae189ab372eb22ac633112b29d4c26e4a8d628 100644 (file)
@@ -35,29 +35,7 @@ all:
        ${CC} ${CCFLAGS} foo.c -o foo -gdwarf-2
        ${FAIL_IF_BAD_MACHO} foo
        ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_EMPTY}
-       rm -f foo
-
-# Test main executable built with stabs has uuid
-       ${CC} ${CCFLAGS} foo.c -o foo -gfull -gstabs+
-       ${FAIL_IF_BAD_MACHO} foo
-       ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_EMPTY}
-
-# Test main executable built with dwarf and -no_uuid does not have uuid
-       ${CC} ${CCFLAGS} foo.c -o foo -Wl,-no_uuid -gdwarf-2
-       ${FAIL_IF_BAD_MACHO} foo
-       ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_STDIN}
-
-# Test ld -r of stabs file has no uuid (llvm does not support stabs, so use gcc)
-       gcc-4.2 -arch ${ARCH} ${CCFLAGS} foo.c -c -o foo.o -gfull -gstabs+
-       ${LD} -arch ${ARCH} foo.o -r -o foo2.o
-       ${OTOOL} -hlv foo2.o | grep LC_UUID | ${FAIL_IF_STDIN}
-
-# Test ld -r of two files one with uuid produces a uuid
-       ${CC} ${CCFLAGS} foo.c -c -o foo.o -gdwarf-2
-       ${LD} -arch ${ARCH} foo.o -r -o foo2.o
-       ${CC} ${CCFLAGS} bar.c -c -gstabs+ -o bar.o
-       ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o
-       ${OTOOL} -hlv foobar.o | grep LC_UUID | ${PASS_IFF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} foo
 
 clean:
-       rm -rf foo foo.o foo2.o bar.o foobar.o foo.dSYM
+       rm -rf foo 
index b56bacf3382e9ad727e87572d0a41550ca515e37..7bcd9a48e03a941d40f45ce73e32de3dc8cbfb18 100644 (file)
@@ -12,16 +12,19 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} -g test.m -c -o test.o
-       libtool -static test.o -o libtest.a
+       ${CC} ${CCFLAGS} -g test2.m -c -o test2.o
+       libtool -static test.o test2.o -o libtest.a
        ${CC} ${CCFLAGS} main.m libtest.a -ObjC -o main -framework Foundation
        nm main | grep mycatmethod1 | ${FAIL_IF_EMPTY}
        nm main | grep mycatmethod2 | ${FAIL_IF_EMPTY}
-       ${LD} -arch ${ARCH} -r -S -keep_private_externs test.o -o test-stripped.o
+       nm main | grep mymethod2 | ${FAIL_IF_EMPTY}
+       ${LD} -arch ${ARCH} -r -S -keep_private_externs test.o test2.o -o test-stripped.o
        libtool -static test-stripped.o -o libtest-stripped.a
        ${CC} ${CCFLAGS} main.m libtest-stripped.a -all_load -dead_strip -o main2 -framework Foundation
        nm main2 | grep mycatmethod1 | ${FAIL_IF_EMPTY}
        nm main2 | grep mycatmethod2 | ${FAIL_IF_EMPTY}
+       nm main2 | grep mymethod2 | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main2
        
 clean:
-       rm -rf test.o test-stripped.o libtest.a libtest-stripped.a main main2 
+       rm -rf test.o test2.o test-stripped.o libtest.a libtest-stripped.a main main2 
diff --git a/unit-tests/test-cases/objc-category-archive/test2.m b/unit-tests/test-cases/objc-category-archive/test2.m
new file mode 100644 (file)
index 0000000..e1e5653
--- /dev/null
@@ -0,0 +1,11 @@
+
+#include <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+- (void) mymethod2;
+@end
+
+@implementation MyClass
+- (void) mymethod2 { }
+@end
+
index 44023e650b3a614009c91f5c89785bd33734bb30..9d719ee387dace62a62feed0b248dfca8c328ff9 100644 (file)
@@ -32,7 +32,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} test.m -g -o test -framework Foundation
+       ${CC} ${CCFLAGS} test.m -g -o test -framework Foundation -Wno-objc-protocol-method-implementation
        nm -ap test | grep GSYM | grep category | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} test
        
index 5652312a4725f5ede4e0d127d92ce0f5c141df79..2bbc5dd525ce396db69d23a8a3cf7df05b0225e6 100644 (file)
@@ -29,7 +29,7 @@ include ${TESTROOT}/include/common.makefile
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
 endif
 
 all:   all-${ARCH}
@@ -40,6 +40,7 @@ all-ppc:
 all-i386: all-rest
 all-x86_64: all-rest
 all-armv6: all-rest
+all-armv7: all-rest
 
 all-rest:
        # check optimzation of category methods
index c452bec0284757d8ea4c62c6ced4a9c80abbb220..c395988affbf667939f4e86105e9e612d9a42505 100644 (file)
@@ -29,7 +29,11 @@ include ${TESTROOT}/include/common.makefile
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+endif
+
+ifeq ($(ARCH),arm)
+       OPTIONS = -isysroot=${IOS_SDK}
 endif
 
 all:   all-${ARCH}
@@ -40,6 +44,7 @@ all-ppc:
 all-i386: all-rest
 all-x86_64: all-rest
 all-armv6: all-rest
+all-armv7: all-rest
 
 all-rest:
        # check optimization can be turned off
index 95cc91d3eb8b3bfd2775604ece6d7079f3ccce1c..5481ba0957ddeacff0748f03f16c9759479615ad 100644 (file)
@@ -30,7 +30,7 @@ SHELL = bash # use bash shell so we can redirect just stderr
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
 endif
 
 all:   all-${FILEARCH}
@@ -52,4 +52,4 @@ all-rest:
        ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
        
 clean:
-       rm -rf  lib*.dylib warnings*.txt
\ No newline at end of file
+       rm -rf  lib*.dylib warnings*.txt
index 1aec6f13ff0797c056464327a1784f0abb5ba341..3e887638055eab6e9598ed90241616c2d28c8699 100644 (file)
@@ -51,7 +51,7 @@ all:
 
        ${CC} ${CCFLAGS} main.c extra.s -DSUBSECTIONS=1 -o main4 -Wl,-order_file -Wl,main4.order 
        ${FAIL_IF_BAD_MACHO} main4
-       nm -n -g -j main4 | nm -njg main4 | egrep '*[1-9]' > main4.nm
+       nm -n -g -j main4 | egrep '_[a-zA-Z]+[1-9]' > main4.nm
        ${PASS_IFF} diff main4.nm main4.expected
 
 
diff --git a/unit-tests/test-cases/pipelined-linking/Makefile b/unit-tests/test-cases/pipelined-linking/Makefile
new file mode 100644 (file)
index 0000000..fe9197f
--- /dev/null
@@ -0,0 +1,74 @@
+##
+# 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
+
+#
+# Validate these pipelined linking cases:
+# - missing pipe
+# - bad file passed via pipe
+# - eof on pipe
+# - success case
+# - differing file orders produce same binary
+#
+# When testing the success case take care to verify that pipelined linking is actually
+# enabled (environment variable is set). Because there is no difference in the command
+# line the test will still succeed with pipelined linking turned off, without testing
+# pipelined linking.
+#
+
+all:
+       # Make some object files
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       ${CC} ${CCFLAGS} cat.c -c -o cat.o
+       ls *.o > filelist
+
+       # missing fifo
+       (LD_PIPELINE_FIFO=bad_fifo ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o partial ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+
+       # partial file list passed via pipe
+       head -1 filelist > pipelineFile
+       (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o partial ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+       ${FAIL_IFF} ${MACHOCHECK} partial 2>&1 > /dev/null
+
+       # bogus file passed via pipe
+       echo "bogus_file.o" > pipelineFile
+       (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -filelist filelist -o bogus ; exit 0) 2>&1 | ${PASS_IFF_STDIN}
+       ${FAIL_IFF} ${MACHOCHECK} bogus 2>&1 > /dev/null
+
+       # success cases - check different orderings of files
+       sort < filelist > pipelineFile
+       (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o normal)
+       ${FAIL_IF_BAD_MACHO} normal
+       sort -r < filelist > pipelineFile
+       (LD_PIPELINE_FIFO=pipelineFile ; export LD_PIPELINE_FIFO ; ${CC} ${CCFLAGS} -filelist filelist -o reverse)
+       ${FAIL_IF_BAD_MACHO} reverse
+
+       # verify that the same binary was generated using both forward and reverse ordering
+       ${PASS_IFF} cmp reverse normal
+
+
+clean:
+       rm -f *.o filelist partial bogus reverse normal pipelineFile
+
diff --git a/unit-tests/test-cases/pipelined-linking/bar.c b/unit-tests/test-cases/pipelined-linking/bar.c
new file mode 100644 (file)
index 0000000..320c246
--- /dev/null
@@ -0,0 +1,4 @@
+void bar()
+{
+}
+
diff --git a/unit-tests/test-cases/pipelined-linking/cat.c b/unit-tests/test-cases/pipelined-linking/cat.c
new file mode 100644 (file)
index 0000000..0e32166
--- /dev/null
@@ -0,0 +1,4 @@
+void cat()
+{
+}
+
diff --git a/unit-tests/test-cases/pipelined-linking/foo.c b/unit-tests/test-cases/pipelined-linking/foo.c
new file mode 100644 (file)
index 0000000..6e0d320
--- /dev/null
@@ -0,0 +1,10 @@
+
+void foo()
+{
+}
+
+int main()
+{
+return 0;
+}
+
diff --git a/unit-tests/test-cases/static-executable-pie/Makefile b/unit-tests/test-cases/static-executable-pie/Makefile
new file mode 100644 (file)
index 0000000..5854b0f
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# 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
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+RELOC_COUNT = 3
+ifeq (${ARCH},x86_64)
+       RELOC_COUNT = 2
+endif
+
+
+#
+# Test that ld can link a pie static executable
+#
+
+all:
+       ${CC} ${CCFLAGS} test.c -c -o test.o
+       ${CC} ${CCFLAGS} test.o -static -Wl,-pie -o test -e _entry  -nostdlib -Wl,-new_linker
+       otool -rv test | grep __DATA | wc -l | grep ${RELOC_COUNT} | ${FAIL_IF_EMPTY}
+       # verify trying to use absolute addressing fails
+       ${CC} ${CCFLAGS} -static bad.c -c -o bad.o
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} test.o bad.o -static -Wl,-pie -o test.bad -e _entry -nostdlib -Wl,-new_linker 2>/dev/null
+       ${PASS_IFF_GOOD_MACHO} test
+
+clean:
+       rm -rf test test.o bad.o test.bad
+
+
diff --git a/unit-tests/test-cases/static-executable-pie/bad.c b/unit-tests/test-cases/static-executable-pie/bad.c
new file mode 100644 (file)
index 0000000..40f0614
--- /dev/null
@@ -0,0 +1,9 @@
+static int my;
+
+int getmy() 
+{ 
+#if __x86_64__
+       __asm(" .quad _my");
+#endif
+       return my; 
+}
diff --git a/unit-tests/test-cases/static-executable-pie/test.c b/unit-tests/test-cases/static-executable-pie/test.c
new file mode 100644 (file)
index 0000000..4d09a3a
--- /dev/null
@@ -0,0 +1,19 @@
+
+int a;
+int b = 5;
+int* pa = &a;
+int* pb = &b;
+
+int foo()
+{
+       *pa = 4;
+       return a+b;
+}
+
+
+int entry()
+{
+       return foo();
+}
+
+
index 7c2c28fb8fa1237c14fd8bd44d7ffff7892948d2..ba343cc6caf374efcacdb11b5afff419548eff97 100644 (file)
@@ -55,8 +55,8 @@ all:
        ${CC} ${CCFLAGS} main.c libfoo_code.a -o main_code
        nm -m main_code | grep _foo | grep __TEXT | ${FAIL_IF_STDIN}
        # verify warning when code force to override tent
-       ${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo_code.a -o main_code_force 2>main_code_force_warnings.txt
-       grep warning main_code_force_warnings.txt | ${FAIL_IF_EMPTY}
+       #${CC} ${CCFLAGS} main.c -Wl,-force_load,libfoo_code.a -o main_code_force 2>main_code_force_warnings.txt
+       #grep warning main_code_force_warnings.txt | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main_code
 
 clean:
index 568ebc65b67f90c28072463307b5c72d304fd700..2793f3e18cd9f2bec424b1fc5c5846f273503ac5 100644 (file)
@@ -30,7 +30,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       clang ${CCFLAGS} main.c -o main -dead_strip -mmacosx-version-min=10.7
+       ${CC} ${CCFLAGS} main.c -o main -dead_strip -mmacosx-version-min=10.7
        otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY}
        otool -lv main | egrep 'S_THREAD_LOCAL_REGULAR|S_THREAD_LOCAL_ZEROFILL' | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
diff --git a/unit-tests/test-cases/weak_import-undefined/Makefile b/unit-tests/test-cases/weak_import-undefined/Makefile
new file mode 100644 (file)
index 0000000..56e888f
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that setting weak_import on symbols in a linkage unit works
+#
+
+
+run: all
+
+all:   
+       ${CC} ${CCFLAGS} -o weak weak.c -undefined dynamic_lookup
+       ${DYLDINFO} -bind weak | grep _myweakfunc | grep "weak import" | ${FAIL_IF_EMPTY} 
+       ${DYLDINFO} -lazy_bind weak | grep _myweakfunc | grep "weak import" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO}  weak
+       
+clean:
+       rm -rf main
diff --git a/unit-tests/test-cases/weak_import-undefined/weak.c b/unit-tests/test-cases/weak_import-undefined/weak.c
new file mode 100644 (file)
index 0000000..f8e103b
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+char *myweakfunc(void) __attribute__((weak)) ;
+
+int main(int argc, char **argv)
+{
+  if (myweakfunc)
+    printf ("found myweakfunc %s\n", myweakfunc());
+  else
+    printf("Weak func not found\n");
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/weak_import3/Makefile b/unit-tests/test-cases/weak_import3/Makefile
deleted file mode 100644 (file)
index 2c8806d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# @APPLE_LICENSE_HEADER_START@
-#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
-#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
-# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
-##
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-#
-# Test the weak_import attribute works
-#
-
-
-run: all
-
-all:   
-       ${CC} ${CCFLAGS} -c foo.c -o foo.o
-       ${FAIL_IF_BAD_OBJ} foo.o
-
-       ${CC} ${CCFLAGS} -c foo1.c -o foo1.o
-       ${FAIL_IF_BAD_OBJ} foo1.o
-
-       ${PASS_IFF_ERROR} ${CC} ${CCFLAGS} -dynamiclib foo.o foo1.o -o libfoo.dylib 
-
-clean:
-       rm -rf foo.o foo1.o libfoo.dylib
-
-
-#2>/dev/null
\ No newline at end of file
diff --git a/unit-tests/test-cases/weak_import3/comment.txt b/unit-tests/test-cases/weak_import3/comment.txt
deleted file mode 100644 (file)
index 5be42d8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Test the weak_import attribute works
diff --git a/unit-tests/test-cases/weak_import3/foo.c b/unit-tests/test-cases/weak_import3/foo.c
deleted file mode 100644 (file)
index 900b052..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-#include "foo.h"
-
-void func1() {}
-void func2() {}
-void func3() {}
-void func4() {}
-
-
-int data1 = 0;
-int data2 = 0; // weak_import initialized
-int data3;
-int data4;             // weak_import uninitialized
-int data5 = 0;
-int data6 = 0; // weak_import 
-
diff --git a/unit-tests/test-cases/weak_import3/foo.h b/unit-tests/test-cases/weak_import3/foo.h
deleted file mode 100644 (file)
index f455515..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-extern void func1();
-extern void func2() __attribute__((weak_import));
-extern void func3();
-extern void func4() __attribute__((weak_import));
-
-extern int data1;
-extern int data2 __attribute__((weak_import));
-extern int data3;
-extern int data4 __attribute__((weak_import));
-extern int data5;
-extern int data6 __attribute__((weak_import));
-
-
-
diff --git a/unit-tests/test-cases/weak_import3/foo1.c b/unit-tests/test-cases/weak_import3/foo1.c
deleted file mode 100644 (file)
index 392a5b7..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#include "foo.h"
-
-int data4;             // foo.c also has weak_import uninitialized
-
diff --git a/unit-tests/test-cases/weak_import3/main.c b/unit-tests/test-cases/weak_import3/main.c
deleted file mode 100644 (file)
index 3266aed..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-#include "foo.h"
-
-
-int* pdata5 = &data5;
-int* pdata6 = &data6;
-
-
-int main (void)
-{
-       // make non-lazy reference to func3 and func4
-       if ( &func3 == &func4 ) {
-               // make lazy reference to func3 and func4
-               func1();
-               func2();
-       }
-   
-   return data1 + data2 + data3 + data4;
-}
-